@shopify/cli-kit 3.48.1 → 3.48.2
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/private/node/ui/components/ConcurrentOutput.d.ts +17 -6
- package/dist/private/node/ui/components/ConcurrentOutput.js +50 -12
- package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.test.js +17 -9
- package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
- package/dist/private/node/ui.d.ts +1 -1
- package/dist/private/node/ui.js +3 -3
- package/dist/private/node/ui.js.map +1 -1
- package/dist/public/common/version.d.ts +1 -1
- package/dist/public/common/version.js +1 -1
- package/dist/public/common/version.js.map +1 -1
- package/dist/public/node/base-command.d.ts +1 -0
- package/dist/public/node/base-command.js +3 -0
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/hooks/postrun.js +23 -0
- package/dist/public/node/hooks/postrun.js.map +1 -1
- package/dist/public/node/system.js +1 -1
- package/dist/public/node/system.js.map +1 -1
- package/dist/public/node/tree-kill.d.ts +6 -0
- package/dist/public/node/tree-kill.js +12 -0
- package/dist/public/node/tree-kill.js.map +1 -0
- package/dist/public/node/ui.d.ts +4 -1
- package/dist/public/node/ui.js +6 -4
- package/dist/public/node/ui.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/dist/private/node/tree-kill.d.ts +0 -1
- package/dist/private/node/tree-kill.js +0 -7
- package/dist/private/node/tree-kill.js.map +0 -1
|
@@ -1,23 +1,34 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
2
|
import { OutputProcess } from '../../../../public/node/output.js';
|
|
3
|
-
import {
|
|
3
|
+
import { AbortController } from '../../../../public/node/abort.js';
|
|
4
4
|
import { FunctionComponent } from 'react';
|
|
5
5
|
import { Key } from 'ink';
|
|
6
6
|
import { Writable } from 'stream';
|
|
7
7
|
export type WritableStream = (process: OutputProcess, index: number) => Writable;
|
|
8
|
+
export interface Footer {
|
|
9
|
+
shortcuts: Shortcut[];
|
|
10
|
+
subTitle?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface FooterContext {
|
|
13
|
+
footer?: Footer;
|
|
14
|
+
updateShortcut: (prevShortcut: Shortcut, newShortcut: Shortcut) => void;
|
|
15
|
+
updateSubTitle: (subTitle: string) => void;
|
|
16
|
+
}
|
|
8
17
|
interface Shortcut {
|
|
9
18
|
key: string;
|
|
10
19
|
action: string;
|
|
20
|
+
syncer?: (footerContext: FooterContext, abortController: AbortController) => void;
|
|
21
|
+
state?: {
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
};
|
|
11
24
|
}
|
|
12
25
|
export interface ConcurrentOutputProps {
|
|
13
26
|
processes: OutputProcess[];
|
|
14
|
-
|
|
27
|
+
abortController: AbortController;
|
|
15
28
|
showTimestamps?: boolean;
|
|
16
29
|
onInput?: (input: string, key: Key, exit: () => void) => void;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
subTitle?: string;
|
|
20
|
-
};
|
|
30
|
+
onInputAsync?: (input: string, key: Key, exit: () => void, footerContext: FooterContext) => Promise<void>;
|
|
31
|
+
footer?: Footer;
|
|
21
32
|
keepRunningAfterProcessesResolve?: boolean;
|
|
22
33
|
}
|
|
23
34
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { treeKill } from '../../../../public/node/tree-kill.js';
|
|
1
2
|
import { handleCtrlC } from '../../ui.js';
|
|
2
3
|
import { addOrUpdateConcurrentUIEventOutput } from '../../demo-recorder.js';
|
|
3
|
-
import { treeKill } from '../../tree-kill.js';
|
|
4
4
|
import useAbortSignal from '../hooks/use-abort-signal.js';
|
|
5
5
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
6
6
|
import { Box, Static, Text, useInput, useStdin, useApp } from 'ink';
|
|
@@ -60,12 +60,13 @@ function currentTime() {
|
|
|
60
60
|
*
|
|
61
61
|
* ```
|
|
62
62
|
*/
|
|
63
|
-
const ConcurrentOutput = ({ processes,
|
|
63
|
+
const ConcurrentOutput = ({ processes, abortController, showTimestamps = true, onInput, onInputAsync, footer, keepRunningAfterProcessesResolve, }) => {
|
|
64
64
|
const [processOutput, setProcessOutput] = useState([]);
|
|
65
65
|
const { exit: unmountInk } = useApp();
|
|
66
66
|
const prefixColumnSize = Math.max(...processes.map((process) => process.prefix.length));
|
|
67
67
|
const { isRawModeSupported } = useStdin();
|
|
68
68
|
const [state, setState] = useState(ConcurrentOutputState.Running);
|
|
69
|
+
const [footerContent, setFooterContent] = useState(footer);
|
|
69
70
|
const concurrentColors = useMemo(() => ['yellow', 'cyan', 'magenta', 'green', 'blue'], []);
|
|
70
71
|
const lineColor = useCallback((index) => {
|
|
71
72
|
const colorIndex = index < concurrentColors.length ? index : index % concurrentColors.length;
|
|
@@ -88,19 +89,56 @@ const ConcurrentOutput = ({ processes, abortSignal, showTimestamps = true, onInp
|
|
|
88
89
|
},
|
|
89
90
|
});
|
|
90
91
|
}, [footer, lineColor]);
|
|
91
|
-
const { isAborted } = useAbortSignal(
|
|
92
|
+
const { isAborted } = useAbortSignal(abortController.signal);
|
|
92
93
|
const useShortcuts = isRawModeSupported && state === ConcurrentOutputState.Running && !isAborted;
|
|
94
|
+
const updateShortcut = (prevShortcut, newShortcut) => {
|
|
95
|
+
if (!footerContent)
|
|
96
|
+
return;
|
|
97
|
+
const newFooterContent = { ...footerContent };
|
|
98
|
+
newFooterContent.shortcuts.map((short) => {
|
|
99
|
+
if (short.key === prevShortcut.key) {
|
|
100
|
+
short.action = newShortcut.action;
|
|
101
|
+
short.key = newShortcut.key;
|
|
102
|
+
short.state = newShortcut.state;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
setFooterContent(newFooterContent);
|
|
106
|
+
};
|
|
107
|
+
const updateSubTitle = (subTitle) => {
|
|
108
|
+
if (!footerContent)
|
|
109
|
+
return;
|
|
110
|
+
setFooterContent({ ...footerContent, subTitle });
|
|
111
|
+
};
|
|
112
|
+
const runShortcutSyncs = () => {
|
|
113
|
+
footerContent?.shortcuts?.forEach((shortcut) => {
|
|
114
|
+
if (shortcut.syncer)
|
|
115
|
+
shortcut.syncer({ footer: footerContent, updateShortcut, updateSubTitle }, abortController);
|
|
116
|
+
});
|
|
117
|
+
};
|
|
93
118
|
useInput((input, key) => {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
119
|
+
const exit = abortController ? () => abortController.abort() : () => treeKill('SIGINT');
|
|
120
|
+
handleCtrlC(input, key, exit);
|
|
121
|
+
const triggerOnInput = async () => {
|
|
122
|
+
if (onInput) {
|
|
123
|
+
onInput(input, key, exit);
|
|
124
|
+
}
|
|
125
|
+
else if (onInputAsync) {
|
|
126
|
+
await onInputAsync(input, key, exit, { footer: footerContent, updateShortcut, updateSubTitle });
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
130
|
+
triggerOnInput();
|
|
131
|
+
}, { isActive: (typeof onInput !== 'undefined' || typeof onInputAsync !== 'undefined') && useShortcuts });
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
runShortcutSyncs();
|
|
134
|
+
}, []);
|
|
97
135
|
useEffect(() => {
|
|
98
136
|
;
|
|
99
137
|
(() => {
|
|
100
138
|
return Promise.all(processes.map(async (process, index) => {
|
|
101
139
|
const stdout = writableStream(process, index);
|
|
102
140
|
const stderr = writableStream(process, index);
|
|
103
|
-
await process.action(stdout, stderr,
|
|
141
|
+
await process.action(stdout, stderr, abortController.signal);
|
|
104
142
|
}));
|
|
105
143
|
})()
|
|
106
144
|
.then(() => {
|
|
@@ -113,7 +151,7 @@ const ConcurrentOutput = ({ processes, abortSignal, showTimestamps = true, onInp
|
|
|
113
151
|
setState(ConcurrentOutputState.Stopped);
|
|
114
152
|
unmountInk(error);
|
|
115
153
|
});
|
|
116
|
-
}, [
|
|
154
|
+
}, [abortController, processes, writableStream, unmountInk, keepRunningAfterProcessesResolve]);
|
|
117
155
|
const { lineVertical } = figures;
|
|
118
156
|
return (React.createElement(React.Fragment, null,
|
|
119
157
|
React.createElement(Static, { items: processOutput }, (chunk, index) => {
|
|
@@ -133,8 +171,8 @@ const ConcurrentOutput = ({ processes, abortSignal, showTimestamps = true, onInp
|
|
|
133
171
|
" ",
|
|
134
172
|
line)))))));
|
|
135
173
|
}),
|
|
136
|
-
|
|
137
|
-
useShortcuts ? (React.createElement(Box, { flexDirection: "column" },
|
|
174
|
+
footerContent && !isAborted ? (React.createElement(Box, { marginY: 1, paddingTop: 1, flexDirection: "column", flexGrow: 1, borderStyle: "single", borderBottom: false, borderLeft: false, borderRight: false, borderTop: true },
|
|
175
|
+
useShortcuts ? (React.createElement(Box, { flexDirection: "column" }, footerContent.shortcuts.map((shortcut, index) => (React.createElement(Text, { key: index },
|
|
138
176
|
figures.pointerSmall,
|
|
139
177
|
" Press ",
|
|
140
178
|
React.createElement(Text, { bold: true }, shortcut.key),
|
|
@@ -142,8 +180,8 @@ const ConcurrentOutput = ({ processes, abortSignal, showTimestamps = true, onInp
|
|
|
142
180
|
figures.lineVertical,
|
|
143
181
|
" ",
|
|
144
182
|
shortcut.action))))) : null,
|
|
145
|
-
|
|
146
|
-
React.createElement(Text, null,
|
|
183
|
+
footerContent.subTitle ? (React.createElement(Box, { marginTop: useShortcuts ? 1 : 0 },
|
|
184
|
+
React.createElement(Text, null, footerContent.subTitle))) : null)) : null));
|
|
147
185
|
};
|
|
148
186
|
export { ConcurrentOutput };
|
|
149
187
|
//# sourceMappingURL=ConcurrentOutput.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConcurrentOutput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {OutputProcess} from '../../../../public/node/output.js'\nimport {AbortSignal} from '../../../../public/node/abort.js'\nimport {handleCtrlC} from '../../ui.js'\nimport {addOrUpdateConcurrentUIEventOutput} from '../../demo-recorder.js'\nimport {treeKill} from '../../tree-kill.js'\nimport useAbortSignal from '../hooks/use-abort-signal.js'\nimport React, {FunctionComponent, useCallback, useEffect, useMemo, useState} from 'react'\nimport {Box, Key, Static, Text, useInput, TextProps, useStdin, useApp} from 'ink'\nimport stripAnsi from 'strip-ansi'\nimport figures from 'figures'\nimport {Writable} from 'stream'\n\nexport type WritableStream = (process: OutputProcess, index: number) => Writable\n\ninterface Shortcut {\n key: string\n action: string\n}\nexport interface ConcurrentOutputProps {\n processes: OutputProcess[]\n abortSignal: AbortSignal\n showTimestamps?: boolean\n onInput?: (input: string, key: Key, exit: () => void) => void\n footer?: {\n shortcuts: Shortcut[]\n subTitle?: string\n }\n // If set, the component is not automatically unmounted once the processes have all finished\n keepRunningAfterProcessesResolve?: boolean\n}\ninterface Chunk {\n color: TextProps['color']\n prefix: string\n lines: string[]\n}\n\nenum ConcurrentOutputState {\n Running = 'running',\n Stopped = 'stopped',\n}\n\nfunction addLeadingZero(number: number) {\n if (number < 10) {\n return `0${number}`\n } else {\n return number.toString()\n }\n}\n\nfunction currentTime() {\n const currentDateTime = new Date()\n\n const hours = addLeadingZero(currentDateTime.getHours())\n const minutes = addLeadingZero(currentDateTime.getMinutes())\n const seconds = addLeadingZero(currentDateTime.getSeconds())\n\n return `${hours}:${minutes}:${seconds}`\n}\n\n/**\n * Renders output from concurrent processes to the terminal.\n * Output will be divided in a three column layout\n * with the left column containing the timestamp,\n * the right column containing the output,\n * and the middle column containing the process prefix.\n * Every process will be rendered with a different color, up to 4 colors.\n *\n * For example running `shopify app dev`:\n *\n * ```shell\n * 2022-10-10 13:11:03 | backend | npm\n * 2022-10-10 13:11:03 | backend | WARN ignoring workspace config at ...\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | > shopify-app-template-node@0.1.0 dev\n * 2022-10-10 13:11:03 | backend | > cross-env NODE_ENV=development nodemon backend/index.js --watch ./backend\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend | > starter-react-frontend-app@0.1.0 dev\n * 2022-10-10 13:11:03 | frontend | > cross-env NODE_ENV=development node vite-server.js\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | [nodemon] to restart at any time, enter `rs`\n * 2022-10-10 13:11:03 | backend | [nodemon] watching path(s): backend/\n * 2022-10-10 13:11:03 | backend | [nodemon] watching extensions: js,mjs,json\n * 2022-10-10 13:11:03 | backend | [nodemon] starting `node backend/index.js`\n * 2022-10-10 13:11:03 | backend |\n *\n * ```\n */\nconst ConcurrentOutput: FunctionComponent<ConcurrentOutputProps> = ({\n processes,\n abortSignal,\n showTimestamps = true,\n onInput,\n footer,\n keepRunningAfterProcessesResolve,\n}) => {\n const [processOutput, setProcessOutput] = useState<Chunk[]>([])\n const {exit: unmountInk} = useApp()\n const prefixColumnSize = Math.max(...processes.map((process) => process.prefix.length))\n const {isRawModeSupported} = useStdin()\n const [state, setState] = useState<ConcurrentOutputState>(ConcurrentOutputState.Running)\n const concurrentColors: TextProps['color'][] = useMemo(() => ['yellow', 'cyan', 'magenta', 'green', 'blue'], [])\n const lineColor = useCallback(\n (index: number) => {\n const colorIndex = index < concurrentColors.length ? index : index % concurrentColors.length\n return concurrentColors[colorIndex]!\n },\n [concurrentColors],\n )\n\n const writableStream = useCallback(\n (process: OutputProcess, index: number) => {\n return new Writable({\n write(chunk, _encoding, next) {\n const lines = stripAnsi(chunk.toString('utf8').replace(/(\\n)$/, '')).split(/\\n/)\n addOrUpdateConcurrentUIEventOutput({prefix: process.prefix, index, output: lines.join('\\n')}, {footer})\n\n setProcessOutput((previousProcessOutput) => [\n ...previousProcessOutput,\n {\n color: lineColor(index),\n prefix: process.prefix,\n lines,\n },\n ])\n\n next()\n },\n })\n },\n [footer, lineColor],\n )\n\n const {isAborted} = useAbortSignal(abortSignal)\n const useShortcuts = isRawModeSupported && state === ConcurrentOutputState.Running && !isAborted\n\n useInput(\n (input, key) => {\n handleCtrlC(input, key)\n\n onInput!(input, key, () => treeKill('SIGINT'))\n },\n {isActive: typeof onInput !== 'undefined' && useShortcuts},\n )\n\n useEffect(() => {\n ;(() => {\n return Promise.all(\n processes.map(async (process, index) => {\n const stdout = writableStream(process, index)\n const stderr = writableStream(process, index)\n\n await process.action(stdout, stderr, abortSignal)\n }),\n )\n })()\n .then(() => {\n if (!keepRunningAfterProcessesResolve) {\n setState(ConcurrentOutputState.Stopped)\n unmountInk()\n }\n })\n .catch((error) => {\n setState(ConcurrentOutputState.Stopped)\n unmountInk(error)\n })\n }, [abortSignal, processes, writableStream, unmountInk, keepRunningAfterProcessesResolve])\n\n const {lineVertical} = figures\n\n return (\n <>\n <Static items={processOutput}>\n {(chunk, index) => {\n const prefixBuffer = ' '.repeat(prefixColumnSize - chunk.prefix.length)\n return (\n <Box flexDirection=\"column\" key={index}>\n {chunk.lines.map((line, index) => (\n <Box key={index} flexDirection=\"row\">\n <Text color={chunk.color}>\n {showTimestamps ? (\n <Text>\n {currentTime()} {lineVertical}{' '}\n </Text>\n ) : null}\n\n <Text>\n {chunk.prefix}\n {prefixBuffer} {lineVertical} {line}\n </Text>\n </Text>\n </Box>\n ))}\n </Box>\n )\n }}\n </Static>\n {footer ? (\n <Box marginY={1} flexDirection=\"column\" flexGrow={1}>\n {useShortcuts ? (\n <Box flexDirection=\"column\">\n {footer.shortcuts.map((shortcut, index) => (\n <Text key={index}>\n {figures.pointerSmall} Press <Text bold>{shortcut.key}</Text> {figures.lineVertical} {shortcut.action}\n </Text>\n ))}\n </Box>\n ) : null}\n {footer.subTitle ? (\n <Box marginTop={useShortcuts ? 1 : 0}>\n <Text>{footer.subTitle}</Text>\n </Box>\n ) : null}\n </Box>\n ) : null}\n </>\n )\n}\n\nexport {ConcurrentOutput}\n"]}
|
|
1
|
+
{"version":3,"file":"ConcurrentOutput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {OutputProcess} from '../../../../public/node/output.js'\nimport {AbortController} from '../../../../public/node/abort.js'\nimport {treeKill} from '../../../../public/node/tree-kill.js'\nimport {handleCtrlC} from '../../ui.js'\nimport {addOrUpdateConcurrentUIEventOutput} from '../../demo-recorder.js'\nimport useAbortSignal from '../hooks/use-abort-signal.js'\nimport React, {FunctionComponent, useCallback, useEffect, useMemo, useState} from 'react'\nimport {Box, Key, Static, Text, useInput, TextProps, useStdin, useApp} from 'ink'\nimport stripAnsi from 'strip-ansi'\nimport figures from 'figures'\nimport {Writable} from 'stream'\n\nexport type WritableStream = (process: OutputProcess, index: number) => Writable\n\nexport interface Footer {\n shortcuts: Shortcut[]\n subTitle?: string\n}\n\nexport interface FooterContext {\n footer?: Footer\n updateShortcut: (prevShortcut: Shortcut, newShortcut: Shortcut) => void\n updateSubTitle: (subTitle: string) => void\n}\n\ninterface Shortcut {\n key: string\n action: string\n syncer?: (footerContext: FooterContext, abortController: AbortController) => void\n state?: {\n [key: string]: unknown\n }\n}\nexport interface ConcurrentOutputProps {\n processes: OutputProcess[]\n abortController: AbortController\n showTimestamps?: boolean\n onInput?: (input: string, key: Key, exit: () => void) => void\n onInputAsync?: (input: string, key: Key, exit: () => void, footerContext: FooterContext) => Promise<void>\n footer?: Footer\n // If set, the component is not automatically unmounted once the processes have all finished\n keepRunningAfterProcessesResolve?: boolean\n}\ninterface Chunk {\n color: TextProps['color']\n prefix: string\n lines: string[]\n}\nenum ConcurrentOutputState {\n Running = 'running',\n Stopped = 'stopped',\n}\nfunction addLeadingZero(number: number) {\n if (number < 10) {\n return `0${number}`\n } else {\n return number.toString()\n }\n}\nfunction currentTime() {\n const currentDateTime = new Date()\n const hours = addLeadingZero(currentDateTime.getHours())\n const minutes = addLeadingZero(currentDateTime.getMinutes())\n const seconds = addLeadingZero(currentDateTime.getSeconds())\n return `${hours}:${minutes}:${seconds}`\n}\n/**\n * Renders output from concurrent processes to the terminal.\n * Output will be divided in a three column layout\n * with the left column containing the timestamp,\n * the right column containing the output,\n * and the middle column containing the process prefix.\n * Every process will be rendered with a different color, up to 4 colors.\n *\n * For example running `shopify app dev`:\n *\n * ```shell\n * 2022-10-10 13:11:03 | backend | npm\n * 2022-10-10 13:11:03 | backend | WARN ignoring workspace config at ...\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | > shopify-app-template-node@0.1.0 dev\n * 2022-10-10 13:11:03 | backend | > cross-env NODE_ENV=development nodemon backend/index.js --watch ./backend\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend | > starter-react-frontend-app@0.1.0 dev\n * 2022-10-10 13:11:03 | frontend | > cross-env NODE_ENV=development node vite-server.js\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | frontend |\n * 2022-10-10 13:11:03 | backend |\n * 2022-10-10 13:11:03 | backend | [nodemon] to restart at any time, enter `rs`\n * 2022-10-10 13:11:03 | backend | [nodemon] watching path(s): backend/\n * 2022-10-10 13:11:03 | backend | [nodemon] watching extensions: js,mjs,json\n * 2022-10-10 13:11:03 | backend | [nodemon] starting `node backend/index.js`\n * 2022-10-10 13:11:03 | backend |\n *\n * ```\n */\nconst ConcurrentOutput: FunctionComponent<ConcurrentOutputProps> = ({\n processes,\n abortController,\n showTimestamps = true,\n onInput,\n onInputAsync,\n footer,\n keepRunningAfterProcessesResolve,\n}) => {\n const [processOutput, setProcessOutput] = useState<Chunk[]>([])\n const {exit: unmountInk} = useApp()\n const prefixColumnSize = Math.max(...processes.map((process) => process.prefix.length))\n const {isRawModeSupported} = useStdin()\n const [state, setState] = useState<ConcurrentOutputState>(ConcurrentOutputState.Running)\n const [footerContent, setFooterContent] = useState<Footer | undefined>(footer)\n const concurrentColors: TextProps['color'][] = useMemo(() => ['yellow', 'cyan', 'magenta', 'green', 'blue'], [])\n const lineColor = useCallback(\n (index: number) => {\n const colorIndex = index < concurrentColors.length ? index : index % concurrentColors.length\n return concurrentColors[colorIndex]!\n },\n [concurrentColors],\n )\n const writableStream = useCallback(\n (process: OutputProcess, index: number) => {\n return new Writable({\n write(chunk, _encoding, next) {\n const lines = stripAnsi(chunk.toString('utf8').replace(/(\\n)$/, '')).split(/\\n/)\n addOrUpdateConcurrentUIEventOutput({prefix: process.prefix, index, output: lines.join('\\n')}, {footer})\n setProcessOutput((previousProcessOutput) => [\n ...previousProcessOutput,\n {\n color: lineColor(index),\n prefix: process.prefix,\n lines,\n },\n ])\n next()\n },\n })\n },\n [footer, lineColor],\n )\n const {isAborted} = useAbortSignal(abortController.signal)\n const useShortcuts = isRawModeSupported && state === ConcurrentOutputState.Running && !isAborted\n\n const updateShortcut = (prevShortcut: Shortcut, newShortcut: Shortcut) => {\n if (!footerContent) return\n const newFooterContent = {...footerContent}\n\n newFooterContent.shortcuts.map((short) => {\n if (short.key === prevShortcut.key) {\n short.action = newShortcut.action\n short.key = newShortcut.key\n short.state = newShortcut.state\n }\n })\n setFooterContent(newFooterContent)\n }\n\n const updateSubTitle = (subTitle: string) => {\n if (!footerContent) return\n\n setFooterContent({...footerContent, subTitle})\n }\n\n const runShortcutSyncs = () => {\n footerContent?.shortcuts?.forEach((shortcut) => {\n if (shortcut.syncer) shortcut.syncer({footer: footerContent, updateShortcut, updateSubTitle}, abortController)\n })\n }\n\n useInput(\n (input, key) => {\n const exit = abortController ? () => abortController.abort() : () => treeKill('SIGINT')\n\n handleCtrlC(input, key, exit)\n\n const triggerOnInput = async () => {\n if (onInput) {\n onInput(input, key, exit)\n } else if (onInputAsync) {\n await onInputAsync(input, key, exit, {footer: footerContent, updateShortcut, updateSubTitle})\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n triggerOnInput()\n },\n {isActive: (typeof onInput !== 'undefined' || typeof onInputAsync !== 'undefined') && useShortcuts},\n )\n\n useEffect(() => {\n runShortcutSyncs()\n }, [])\n\n useEffect(() => {\n ;(() => {\n return Promise.all(\n processes.map(async (process, index) => {\n const stdout = writableStream(process, index)\n const stderr = writableStream(process, index)\n await process.action(stdout, stderr, abortController.signal)\n }),\n )\n })()\n .then(() => {\n if (!keepRunningAfterProcessesResolve) {\n setState(ConcurrentOutputState.Stopped)\n unmountInk()\n }\n })\n .catch((error) => {\n setState(ConcurrentOutputState.Stopped)\n unmountInk(error)\n })\n }, [abortController, processes, writableStream, unmountInk, keepRunningAfterProcessesResolve])\n const {lineVertical} = figures\n return (\n <>\n <Static items={processOutput}>\n {(chunk, index) => {\n const prefixBuffer = ' '.repeat(prefixColumnSize - chunk.prefix.length)\n return (\n <Box flexDirection=\"column\" key={index}>\n {chunk.lines.map((line, index) => (\n <Box key={index} flexDirection=\"row\">\n <Text color={chunk.color}>\n {showTimestamps ? (\n <Text>\n {currentTime()} {lineVertical}{' '}\n </Text>\n ) : null}\n <Text>\n {chunk.prefix}\n {prefixBuffer} {lineVertical} {line}\n </Text>\n </Text>\n </Box>\n ))}\n </Box>\n )\n }}\n </Static>\n {footerContent && !isAborted ? (\n <Box\n marginY={1}\n paddingTop={1}\n flexDirection=\"column\"\n flexGrow={1}\n borderStyle=\"single\"\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n borderTop\n >\n {useShortcuts ? (\n <Box flexDirection=\"column\">\n {footerContent.shortcuts.map((shortcut, index) => (\n <Text key={index}>\n {figures.pointerSmall} Press <Text bold>{shortcut.key}</Text> {figures.lineVertical} {shortcut.action}\n </Text>\n ))}\n </Box>\n ) : null}\n {footerContent.subTitle ? (\n <Box marginTop={useShortcuts ? 1 : 0}>\n <Text>{footerContent.subTitle}</Text>\n </Box>\n ) : null}\n </Box>\n ) : null}\n </>\n )\n}\nexport {ConcurrentOutput}\n"]}
|
|
@@ -37,7 +37,7 @@ describe('ConcurrentOutput', () => {
|
|
|
37
37
|
},
|
|
38
38
|
};
|
|
39
39
|
// When
|
|
40
|
-
const renderInstance = render(React.createElement(ConcurrentOutput, { processes: [backendProcess, frontendProcess],
|
|
40
|
+
const renderInstance = render(React.createElement(ConcurrentOutput, { processes: [backendProcess, frontendProcess], abortController: new AbortController(), footer: {
|
|
41
41
|
shortcuts: [
|
|
42
42
|
{
|
|
43
43
|
key: 'p',
|
|
@@ -60,6 +60,8 @@ describe('ConcurrentOutput', () => {
|
|
|
60
60
|
00:00:00 │ frontend │ second frontend message
|
|
61
61
|
00:00:00 │ frontend │ third frontend message
|
|
62
62
|
|
|
63
|
+
────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
64
|
+
|
|
63
65
|
› Press p │ preview in your browser
|
|
64
66
|
› Press q │ quit
|
|
65
67
|
|
|
@@ -99,7 +101,7 @@ describe('ConcurrentOutput', () => {
|
|
|
99
101
|
},
|
|
100
102
|
};
|
|
101
103
|
// When
|
|
102
|
-
const renderInstance = render(React.createElement(ConcurrentOutput, { processes: [backendProcess, frontendProcess],
|
|
104
|
+
const renderInstance = render(React.createElement(ConcurrentOutput, { processes: [backendProcess, frontendProcess], abortController: new AbortController(), footer: {
|
|
103
105
|
shortcuts: [
|
|
104
106
|
{
|
|
105
107
|
key: 'p',
|
|
@@ -122,6 +124,8 @@ describe('ConcurrentOutput', () => {
|
|
|
122
124
|
00:00:00 │ frontend │ second frontend message
|
|
123
125
|
00:00:00 │ frontend │ third frontend message
|
|
124
126
|
|
|
127
|
+
────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
128
|
+
|
|
125
129
|
Preview URL: https://shopify.com
|
|
126
130
|
"
|
|
127
131
|
`);
|
|
@@ -135,7 +139,7 @@ describe('ConcurrentOutput', () => {
|
|
|
135
139
|
},
|
|
136
140
|
};
|
|
137
141
|
const onInput = vi.fn();
|
|
138
|
-
const renderInstance = render(React.createElement(ConcurrentOutput, { processes: [neverEndingProcess], onInput: (input, key) => onInput(input, key),
|
|
142
|
+
const renderInstance = render(React.createElement(ConcurrentOutput, { processes: [neverEndingProcess], onInput: (input, key) => onInput(input, key), abortController: new AbortController() }));
|
|
139
143
|
await waitForInputsToBeReady();
|
|
140
144
|
renderInstance.stdin.write('a');
|
|
141
145
|
expect(onInput).toHaveBeenCalledTimes(1);
|
|
@@ -155,7 +159,7 @@ describe('ConcurrentOutput', () => {
|
|
|
155
159
|
},
|
|
156
160
|
};
|
|
157
161
|
// When
|
|
158
|
-
const renderInstance = render(React.createElement(ConcurrentOutput, { processes: [backendProcess],
|
|
162
|
+
const renderInstance = render(React.createElement(ConcurrentOutput, { processes: [backendProcess], abortController: abortController, footer: {
|
|
159
163
|
shortcuts: [
|
|
160
164
|
{
|
|
161
165
|
key: 'p',
|
|
@@ -174,8 +178,6 @@ describe('ConcurrentOutput', () => {
|
|
|
174
178
|
"00:00:00 │ backend │ first backend message
|
|
175
179
|
00:00:00 │ backend │ second backend message
|
|
176
180
|
00:00:00 │ backend │ third backend message
|
|
177
|
-
|
|
178
|
-
Preview URL: https://shopify.com
|
|
179
181
|
"
|
|
180
182
|
`);
|
|
181
183
|
await expect(promise).resolves.toEqual(undefined);
|
|
@@ -192,7 +194,7 @@ describe('ConcurrentOutput', () => {
|
|
|
192
194
|
},
|
|
193
195
|
};
|
|
194
196
|
// When
|
|
195
|
-
const renderInstance = render(React.createElement(ConcurrentOutput, { processes: [backendProcess],
|
|
197
|
+
const renderInstance = render(React.createElement(ConcurrentOutput, { processes: [backendProcess], abortController: new AbortController(), footer: {
|
|
196
198
|
shortcuts: [
|
|
197
199
|
{
|
|
198
200
|
key: 'p',
|
|
@@ -211,6 +213,8 @@ describe('ConcurrentOutput', () => {
|
|
|
211
213
|
00:00:00 │ backend │ second backend message
|
|
212
214
|
00:00:00 │ backend │ third backend message
|
|
213
215
|
|
|
216
|
+
────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
217
|
+
|
|
214
218
|
Preview URL: https://shopify.com
|
|
215
219
|
"
|
|
216
220
|
`);
|
|
@@ -226,7 +230,7 @@ describe('ConcurrentOutput', () => {
|
|
|
226
230
|
},
|
|
227
231
|
};
|
|
228
232
|
// When
|
|
229
|
-
const renderInstance = render(React.createElement(ConcurrentOutput, { processes: [backendProcess],
|
|
233
|
+
const renderInstance = render(React.createElement(ConcurrentOutput, { processes: [backendProcess], abortController: new AbortController(), footer: {
|
|
230
234
|
shortcuts: [
|
|
231
235
|
{
|
|
232
236
|
key: 'p',
|
|
@@ -245,6 +249,8 @@ describe('ConcurrentOutput', () => {
|
|
|
245
249
|
00:00:00 │ backend │ second backend message
|
|
246
250
|
00:00:00 │ backend │ third backend message
|
|
247
251
|
|
|
252
|
+
────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
253
|
+
|
|
248
254
|
Preview URL: https://shopify.com
|
|
249
255
|
"
|
|
250
256
|
`);
|
|
@@ -261,7 +267,7 @@ describe('ConcurrentOutput', () => {
|
|
|
261
267
|
},
|
|
262
268
|
};
|
|
263
269
|
// When
|
|
264
|
-
const renderInstance = render(React.createElement(ConcurrentOutput, { processes: [backendProcess],
|
|
270
|
+
const renderInstance = render(React.createElement(ConcurrentOutput, { processes: [backendProcess], abortController: new AbortController(), footer: {
|
|
265
271
|
shortcuts: [
|
|
266
272
|
{
|
|
267
273
|
key: 'p',
|
|
@@ -280,6 +286,8 @@ describe('ConcurrentOutput', () => {
|
|
|
280
286
|
00:00:00 │ backend │ second backend message
|
|
281
287
|
00:00:00 │ backend │ third backend message
|
|
282
288
|
|
|
289
|
+
────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
290
|
+
|
|
283
291
|
› Press p │ preview in your browser
|
|
284
292
|
› Press q │ quit
|
|
285
293
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConcurrentOutput.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,gBAAgB,EAAC,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAC,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,EAAE,KAAK,EAAC,MAAM,qBAAqB,CAAA;AACnG,OAAO,EAAC,eAAe,EAAc,MAAM,kCAAkC,CAAA;AAC7E,OAAO,EAAC,QAAQ,EAAC,MAAM,mCAAmC,CAAA;AAC1D,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAC,MAAM,QAAQ,CAAA;AAGjD,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,IAAI,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QAC3E,QAAQ;QACR,IAAI,qBAAiC,CAAA;QACrC,IAAI,sBAAkC,CAAA;QAEtC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAO,UAAU,OAAO,EAAE,OAAO;YACjE,qBAAqB,GAAG,OAAO,CAAA;QACjC,CAAC,CAAC,CAAA;QAEF,MAAM,eAAe,GAAG,IAAI,OAAO,CAAO,UAAU,OAAO,EAAE,OAAO;YAClE,sBAAsB,GAAG,OAAO,CAAA;QAClC,CAAC,CAAC,CAAA;QAEF,MAAM,cAAc,GAAG;YACrB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBACrC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBAErC,qBAAqB,EAAE,CAAA;YACzB,CAAC;SACF,CAAA;QAED,MAAM,eAAe,GAAG;YACtB,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,cAAc,CAAA;gBAEpB,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAA;gBACvC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBAEtC,sBAAsB,EAAE,CAAA;gBAExB,oCAAoC;gBACpC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YAC7B,CAAC;SACF,CAAA;QACD,OAAO;QAEP,MAAM,cAAc,GAAG,MAAM,CAC3B,oBAAC,gBAAgB,IACf,SAAS,EAAE,CAAC,cAAc,EAAE,eAAe,CAAC,EAC5C,WAAW,EAAE,IAAI,eAAe,EAAE,CAAC,MAAM,EACzC,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,yBAAyB;qBAClC;oBACD;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,MAAM;qBACf;iBACF;gBACD,QAAQ,EAAE,kCAAkC;aAC7C,GACD,CACH,CAAA;QAED,MAAM,eAAe,CAAA;QAErB,OAAO;QACP,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,SAAS,EAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;;;;KAavF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QACpE,QAAQ;QACR,IAAI,qBAAiC,CAAA;QACrC,IAAI,sBAAkC,CAAA;QAEtC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAO,UAAU,OAAO,EAAE,OAAO;YACjE,qBAAqB,GAAG,OAAO,CAAA;QACjC,CAAC,CAAC,CAAA;QAEF,MAAM,eAAe,GAAG,IAAI,OAAO,CAAO,UAAU,OAAO,EAAE,OAAO;YAClE,sBAAsB,GAAG,OAAO,CAAA;QAClC,CAAC,CAAC,CAAA;QAEF,MAAM,cAAc,GAAG;YACrB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBACrC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBAErC,qBAAqB,EAAE,CAAA;YACzB,CAAC;SACF,CAAA;QAED,MAAM,eAAe,GAAG;YACtB,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,cAAc,CAAA;gBAEpB,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAA;gBACvC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBAEtC,sBAAsB,EAAE,CAAA;gBAExB,oCAAoC;gBACpC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YAC7B,CAAC;SACF,CAAA;QACD,OAAO;QAEP,MAAM,cAAc,GAAG,MAAM,CAC3B,oBAAC,gBAAgB,IACf,SAAS,EAAE,CAAC,cAAc,EAAE,eAAe,CAAC,EAC5C,WAAW,EAAE,IAAI,eAAe,EAAE,CAAC,MAAM,EACzC,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,yBAAyB;qBAClC;oBACD;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,MAAM;qBACf;iBACF;gBACD,QAAQ,EAAE,kCAAkC;aAC7C,GACD,EACF,EAAC,KAAK,EAAE,IAAI,KAAK,CAAC,EAAC,KAAK,EAAE,KAAK,EAAC,CAAC,EAAC,CACnC,CAAA;QAED,MAAM,eAAe,CAAA;QAErB,OAAO;QACP,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAC,cAAc,CAAE,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;KAUrG,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC7E,MAAM,kBAAkB,GAAG,IAAI,OAAO,CAAO,UAAU,QAAQ,EAAE,OAAO,IAAG,CAAC,CAAC,CAAA;QAE7E,MAAM,kBAAkB,GAAG;YACzB,MAAM,EAAE,sBAAsB;YAC9B,MAAM,EAAE,KAAK,IAAI,EAAE;gBACjB,MAAM,kBAAkB,CAAA;YAC1B,CAAC;SACF,CAAA;QAED,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;QAEvB,MAAM,cAAc,GAAG,MAAM,CAC3B,oBAAC,gBAAgB,IACf,SAAS,EAAE,CAAC,kBAAkB,CAAC,EAC/B,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAC5C,WAAW,EAAE,IAAI,eAAe,EAAE,CAAC,MAAM,GACzC,CACH,CAAA;QAED,MAAM,sBAAsB,EAAE,CAAA;QAC9B,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC/B,MAAM,CAAC,OAAO,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAA;QACxC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,oFAAoF,EAAE,KAAK,IAAI,EAAE;QACpG,QAAQ;QACR,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAA;QAE7C,MAAM,cAAc,GAAG;YACrB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBACrC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBAErC,oCAAoC;gBACpC,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YAC7B,CAAC;SACF,CAAA;QAED,OAAO;QAEP,MAAM,cAAc,GAAG,MAAM,CAC3B,oBAAC,gBAAgB,IACf,SAAS,EAAE,CAAC,cAAc,CAAC,EAC3B,WAAW,EAAE,eAAe,CAAC,MAAM,EACnC,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,yBAAyB;qBAClC;oBACD;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,MAAM;qBACf;iBACF;gBACD,QAAQ,EAAE,kCAAkC;aAC7C,GACD,CACH,CAAA;QAED,MAAM,OAAO,GAAG,cAAc,CAAC,aAAa,EAAE,CAAA;QAE9C,eAAe,CAAC,KAAK,EAAE,CAAA;QAEvB,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAC,cAAc,CAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;KAOrG,CAAC,CAAA;QAEF,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QAC3E,QAAQ;QACR,MAAM,cAAc,GAAG;YACrB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBACrC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBAErC,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAA;YACzC,CAAC;SACF,CAAA;QAED,OAAO;QAEP,MAAM,cAAc,GAAG,MAAM,CAC3B,oBAAC,gBAAgB,IACf,SAAS,EAAE,CAAC,cAAc,CAAC,EAC3B,WAAW,EAAE,IAAI,eAAe,EAAE,CAAC,MAAM,EACzC,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,yBAAyB;qBAClC;oBACD;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,MAAM;qBACf;iBACF;gBACD,QAAQ,EAAE,kCAAkC;aAC7C,GACD,CACH,CAAA;QAED,MAAM,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,sBAAsB,CAAC,CAAA;QAEzF,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAC,cAAc,CAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;KAOrG,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACzE,QAAQ;QACR,MAAM,cAAc,GAAG;YACrB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBACrC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;YACvC,CAAC;SACF,CAAA;QAED,OAAO;QAEP,MAAM,cAAc,GAAG,MAAM,CAC3B,oBAAC,gBAAgB,IACf,SAAS,EAAE,CAAC,cAAc,CAAC,EAC3B,WAAW,EAAE,IAAI,eAAe,EAAE,CAAC,MAAM,EACzC,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,yBAAyB;qBAClC;oBACD;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,MAAM;qBACf;iBACF;gBACD,QAAQ,EAAE,kCAAkC;aAC7C,GACD,CACH,CAAA;QAED,MAAM,cAAc,CAAC,aAAa,EAAE,CAAA;QAEpC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAC,cAAc,CAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;KAOrG,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,kHAAkH,EAAE,KAAK,IAAI,EAAE;QAClI,MAAM,OAAO,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;QACvB,QAAQ;QACR,MAAM,cAAc,GAAG;YACrB,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,KAAK,EAAE,MAAgB,EAAE,OAAiB,EAAE,OAAoB,EAAE,EAAE;gBAC1E,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;gBACrC,MAAM,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;gBACtC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAA;YACvC,CAAC;SACF,CAAA;QAED,OAAO;QACP,MAAM,cAAc,GAAG,MAAM,CAC3B,oBAAC,gBAAgB,IACf,SAAS,EAAE,CAAC,cAAc,CAAC,EAC3B,WAAW,EAAE,IAAI,eAAe,EAAE,CAAC,MAAM,EACzC,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,yBAAyB;qBAClC;oBACD;wBACE,GAAG,EAAE,GAAG;wBACR,MAAM,EAAE,MAAM;qBACf;iBACF;gBACD,QAAQ,EAAE,kCAAkC;aAC7C,EACD,OAAO,EAAE,OAAO,EAChB,gCAAgC,SAChC,CACH,CAAA;QAED,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAA;QAEzD,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAC,cAAc,CAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;KAUrG,CAAC,CAAA;QAEF,cAAc,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC/B,MAAM,CAAC,OAAO,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAA;QACxC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {ConcurrentOutput} from './ConcurrentOutput.js'\nimport {getLastFrameAfterUnmount, waitForInputsToBeReady, render, Stdin} from '../../testing/ui.js'\nimport {AbortController, AbortSignal} from '../../../../public/node/abort.js'\nimport {unstyled} from '../../../../public/node/output.js'\nimport React from 'react'\nimport {describe, expect, test, vi} from 'vitest'\nimport {Writable} from 'stream'\n\ndescribe('ConcurrentOutput', () => {\n test('renders a stream of concurrent outputs from sub-processes', async () => {\n // Given\n let backendPromiseResolve: () => void\n let frontendPromiseResolve: () => void\n\n const backendPromise = new Promise<void>(function (resolve, _reject) {\n backendPromiseResolve = resolve\n })\n\n const frontendPromise = new Promise<void>(function (resolve, _reject) {\n frontendPromiseResolve = resolve\n })\n\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n backendPromiseResolve()\n },\n }\n\n const frontendProcess = {\n prefix: 'frontend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n await backendPromise\n\n stdout.write('first frontend message')\n stdout.write('second frontend message')\n stdout.write('third frontend message')\n\n frontendPromiseResolve()\n\n // await promise that never resolves\n await new Promise(() => {})\n },\n }\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess, frontendProcess]}\n abortSignal={new AbortController().signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n await frontendPromise\n\n // Then\n expect(unstyled(renderInstance.lastFrame()!.replace(/\\d/g, '0'))).toMatchInlineSnapshot(`\n \"00:00:00 │ backend │ first backend message\n 00:00:00 │ backend │ second backend message\n 00:00:00 │ backend │ third backend message\n 00:00:00 │ frontend │ first frontend message\n 00:00:00 │ frontend │ second frontend message\n 00:00:00 │ frontend │ third frontend message\n\n › Press p │ preview in your browser\n › Press q │ quit\n\n Preview URL: https://shopify.com\n \"\n `)\n })\n\n test(\"doesn't render shortcuts if the stdin is not a TTY\", async () => {\n // Given\n let backendPromiseResolve: () => void\n let frontendPromiseResolve: () => void\n\n const backendPromise = new Promise<void>(function (resolve, _reject) {\n backendPromiseResolve = resolve\n })\n\n const frontendPromise = new Promise<void>(function (resolve, _reject) {\n frontendPromiseResolve = resolve\n })\n\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n backendPromiseResolve()\n },\n }\n\n const frontendProcess = {\n prefix: 'frontend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n await backendPromise\n\n stdout.write('first frontend message')\n stdout.write('second frontend message')\n stdout.write('third frontend message')\n\n frontendPromiseResolve()\n\n // await promise that never resolves\n await new Promise(() => {})\n },\n }\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess, frontendProcess]}\n abortSignal={new AbortController().signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n {stdin: new Stdin({isTTY: false})},\n )\n\n await frontendPromise\n\n // Then\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!.replace(/\\d/g, '0'))).toMatchInlineSnapshot(`\n \"00:00:00 │ backend │ first backend message\n 00:00:00 │ backend │ second backend message\n 00:00:00 │ backend │ third backend message\n 00:00:00 │ frontend │ first frontend message\n 00:00:00 │ frontend │ second frontend message\n 00:00:00 │ frontend │ third frontend message\n\n Preview URL: https://shopify.com\n \"\n `)\n })\n\n test('accepts a onInput function that fires when a key is pressed', async () => {\n const neverEndingPromise = new Promise<void>(function (_resolve, _reject) {})\n\n const neverEndingProcess = {\n prefix: 'never-ending-process',\n action: async () => {\n await neverEndingPromise\n },\n }\n\n const onInput = vi.fn()\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[neverEndingProcess]}\n onInput={(input, key) => onInput(input, key)}\n abortSignal={new AbortController().signal}\n />,\n )\n\n await waitForInputsToBeReady()\n renderInstance.stdin.write('a')\n expect(onInput).toHaveBeenCalledTimes(1)\n expect(onInput.mock.calls[0]![0]).toBe('a')\n })\n\n test('abortController can be used to exit from outside and should preserve static output', async () => {\n // Given\n const abortController = new AbortController()\n\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n // await promise that never resolves\n await new Promise(() => {})\n },\n }\n\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess]}\n abortSignal={abortController.signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n const promise = renderInstance.waitUntilExit()\n\n abortController.abort()\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"00:00:00 │ backend │ first backend message\n 00:00:00 │ backend │ second backend message\n 00:00:00 │ backend │ third backend message\n\n Preview URL: https://shopify.com\n \"\n `)\n\n await expect(promise).resolves.toEqual(undefined)\n })\n\n test('rejects with the error thrown inside one of the processes', async () => {\n // Given\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n throw new Error('something went wrong')\n },\n }\n\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess]}\n abortSignal={new AbortController().signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n await expect(renderInstance.waitUntilExit()).rejects.toThrowError('something went wrong')\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"00:00:00 │ backend │ first backend message\n 00:00:00 │ backend │ second backend message\n 00:00:00 │ backend │ third backend message\n\n Preview URL: https://shopify.com\n \"\n `)\n })\n\n test(\"doesn't render the shortcuts when the processes resolve\", async () => {\n // Given\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n },\n }\n\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess]}\n abortSignal={new AbortController().signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n await renderInstance.waitUntilExit()\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"00:00:00 │ backend │ first backend message\n 00:00:00 │ backend │ second backend message\n 00:00:00 │ backend │ third backend message\n\n Preview URL: https://shopify.com\n \"\n `)\n })\n\n test('renders the shortcuts and accepts inputs when the processes resolve and keepRunningAfterProcessesResolve is true', async () => {\n const onInput = vi.fn()\n // Given\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n },\n }\n\n // When\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess]}\n abortSignal={new AbortController().signal}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n onInput={onInput}\n keepRunningAfterProcessesResolve\n />,\n )\n\n await new Promise((resolve) => setTimeout(resolve, 1000))\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"00:00:00 │ backend │ first backend message\n 00:00:00 │ backend │ second backend message\n 00:00:00 │ backend │ third backend message\n\n › Press p │ preview in your browser\n › Press q │ quit\n\n Preview URL: https://shopify.com\n \"\n `)\n\n renderInstance.stdin.write('a')\n expect(onInput).toHaveBeenCalledTimes(1)\n expect(onInput.mock.calls[0]![0]).toBe('a')\n })\n})\n"]}
|
|
1
|
+
{"version":3,"file":"ConcurrentOutput.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {ConcurrentOutput} from './ConcurrentOutput.js'\nimport {getLastFrameAfterUnmount, waitForInputsToBeReady, render, Stdin} from '../../testing/ui.js'\nimport {AbortController, AbortSignal} from '../../../../public/node/abort.js'\nimport {unstyled} from '../../../../public/node/output.js'\nimport React from 'react'\nimport {describe, expect, test, vi} from 'vitest'\nimport {Writable} from 'stream'\n\ndescribe('ConcurrentOutput', () => {\n test('renders a stream of concurrent outputs from sub-processes', async () => {\n // Given\n let backendPromiseResolve: () => void\n let frontendPromiseResolve: () => void\n\n const backendPromise = new Promise<void>(function (resolve, _reject) {\n backendPromiseResolve = resolve\n })\n\n const frontendPromise = new Promise<void>(function (resolve, _reject) {\n frontendPromiseResolve = resolve\n })\n\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n backendPromiseResolve()\n },\n }\n\n const frontendProcess = {\n prefix: 'frontend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n await backendPromise\n\n stdout.write('first frontend message')\n stdout.write('second frontend message')\n stdout.write('third frontend message')\n\n frontendPromiseResolve()\n\n // await promise that never resolves\n await new Promise(() => {})\n },\n }\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess, frontendProcess]}\n abortController={new AbortController()}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n await frontendPromise\n\n // Then\n expect(unstyled(renderInstance.lastFrame()!.replace(/\\d/g, '0'))).toMatchInlineSnapshot(`\n \"00:00:00 │ backend │ first backend message\n 00:00:00 │ backend │ second backend message\n 00:00:00 │ backend │ third backend message\n 00:00:00 │ frontend │ first frontend message\n 00:00:00 │ frontend │ second frontend message\n 00:00:00 │ frontend │ third frontend message\n\n ────────────────────────────────────────────────────────────────────────────────────────────────────\n\n › Press p │ preview in your browser\n › Press q │ quit\n\n Preview URL: https://shopify.com\n \"\n `)\n })\n\n test(\"doesn't render shortcuts if the stdin is not a TTY\", async () => {\n // Given\n let backendPromiseResolve: () => void\n let frontendPromiseResolve: () => void\n\n const backendPromise = new Promise<void>(function (resolve, _reject) {\n backendPromiseResolve = resolve\n })\n\n const frontendPromise = new Promise<void>(function (resolve, _reject) {\n frontendPromiseResolve = resolve\n })\n\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n backendPromiseResolve()\n },\n }\n\n const frontendProcess = {\n prefix: 'frontend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n await backendPromise\n\n stdout.write('first frontend message')\n stdout.write('second frontend message')\n stdout.write('third frontend message')\n\n frontendPromiseResolve()\n\n // await promise that never resolves\n await new Promise(() => {})\n },\n }\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess, frontendProcess]}\n abortController={new AbortController()}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n {stdin: new Stdin({isTTY: false})},\n )\n\n await frontendPromise\n\n // Then\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!.replace(/\\d/g, '0'))).toMatchInlineSnapshot(`\n \"00:00:00 │ backend │ first backend message\n 00:00:00 │ backend │ second backend message\n 00:00:00 │ backend │ third backend message\n 00:00:00 │ frontend │ first frontend message\n 00:00:00 │ frontend │ second frontend message\n 00:00:00 │ frontend │ third frontend message\n\n ────────────────────────────────────────────────────────────────────────────────────────────────────\n\n Preview URL: https://shopify.com\n \"\n `)\n })\n\n test('accepts a onInput function that fires when a key is pressed', async () => {\n const neverEndingPromise = new Promise<void>(function (_resolve, _reject) {})\n\n const neverEndingProcess = {\n prefix: 'never-ending-process',\n action: async () => {\n await neverEndingPromise\n },\n }\n\n const onInput = vi.fn()\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[neverEndingProcess]}\n onInput={(input, key) => onInput(input, key)}\n abortController={new AbortController()}\n />,\n )\n\n await waitForInputsToBeReady()\n renderInstance.stdin.write('a')\n expect(onInput).toHaveBeenCalledTimes(1)\n expect(onInput.mock.calls[0]![0]).toBe('a')\n })\n\n test('abortController can be used to exit from outside and should preserve static output', async () => {\n // Given\n const abortController = new AbortController()\n\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n // await promise that never resolves\n await new Promise(() => {})\n },\n }\n\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess]}\n abortController={abortController}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n const promise = renderInstance.waitUntilExit()\n\n abortController.abort()\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"00:00:00 │ backend │ first backend message\n 00:00:00 │ backend │ second backend message\n 00:00:00 │ backend │ third backend message\n \"\n `)\n\n await expect(promise).resolves.toEqual(undefined)\n })\n\n test('rejects with the error thrown inside one of the processes', async () => {\n // Given\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n\n throw new Error('something went wrong')\n },\n }\n\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess]}\n abortController={new AbortController()}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n await expect(renderInstance.waitUntilExit()).rejects.toThrowError('something went wrong')\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"00:00:00 │ backend │ first backend message\n 00:00:00 │ backend │ second backend message\n 00:00:00 │ backend │ third backend message\n\n ────────────────────────────────────────────────────────────────────────────────────────────────────\n\n Preview URL: https://shopify.com\n \"\n `)\n })\n\n test(\"doesn't render the shortcuts when the processes resolve\", async () => {\n // Given\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n },\n }\n\n // When\n\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess]}\n abortController={new AbortController()}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n />,\n )\n\n await renderInstance.waitUntilExit()\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"00:00:00 │ backend │ first backend message\n 00:00:00 │ backend │ second backend message\n 00:00:00 │ backend │ third backend message\n\n ────────────────────────────────────────────────────────────────────────────────────────────────────\n\n Preview URL: https://shopify.com\n \"\n `)\n })\n\n test('renders the shortcuts and accepts inputs when the processes resolve and keepRunningAfterProcessesResolve is true', async () => {\n const onInput = vi.fn()\n // Given\n const backendProcess = {\n prefix: 'backend',\n action: async (stdout: Writable, _stderr: Writable, _signal: AbortSignal) => {\n stdout.write('first backend message')\n stdout.write('second backend message')\n stdout.write('third backend message')\n },\n }\n\n // When\n const renderInstance = render(\n <ConcurrentOutput\n processes={[backendProcess]}\n abortController={new AbortController()}\n footer={{\n shortcuts: [\n {\n key: 'p',\n action: 'preview in your browser',\n },\n {\n key: 'q',\n action: 'quit',\n },\n ],\n subTitle: `Preview URL: https://shopify.com`,\n }}\n onInput={onInput}\n keepRunningAfterProcessesResolve\n />,\n )\n\n await new Promise((resolve) => setTimeout(resolve, 1000))\n\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"00:00:00 │ backend │ first backend message\n 00:00:00 │ backend │ second backend message\n 00:00:00 │ backend │ third backend message\n\n ────────────────────────────────────────────────────────────────────────────────────────────────────\n\n › Press p │ preview in your browser\n › Press q │ quit\n\n Preview URL: https://shopify.com\n \"\n `)\n\n renderInstance.stdin.write('a')\n expect(onInput).toHaveBeenCalledTimes(1)\n expect(onInput.mock.calls[0]![0]).toBe('a')\n })\n})\n"]}
|
|
@@ -22,5 +22,5 @@ export declare class Stdout extends EventEmitter {
|
|
|
22
22
|
write: (frame: string) => void;
|
|
23
23
|
lastFrame: () => string | undefined;
|
|
24
24
|
}
|
|
25
|
-
export declare function handleCtrlC(input: string, key: Key): void;
|
|
25
|
+
export declare function handleCtrlC(input: string, key: Key, exit?: () => void): void;
|
|
26
26
|
export {};
|
package/dist/private/node/ui.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { treeKill } from './tree-kill.js';
|
|
2
1
|
import { collectLog, consoleLog, outputWhereAppropriate } from '../../public/node/output.js';
|
|
3
2
|
import { isUnitTest } from '../../public/node/context/local.js';
|
|
3
|
+
import { treeKill } from '../../public/node/tree-kill.js';
|
|
4
4
|
import { render as inkRender } from 'ink';
|
|
5
5
|
import { EventEmitter } from 'events';
|
|
6
6
|
export function renderOnce(element, { logLevel = 'info', logger = consoleLog, renderOptions }) {
|
|
@@ -47,10 +47,10 @@ const renderString = (element, renderOptions) => {
|
|
|
47
47
|
unmount: instance.unmount,
|
|
48
48
|
};
|
|
49
49
|
};
|
|
50
|
-
export function handleCtrlC(input, key) {
|
|
50
|
+
export function handleCtrlC(input, key, exit = () => treeKill('SIGINT')) {
|
|
51
51
|
if (input === 'c' && key.ctrl) {
|
|
52
52
|
// Exceptions thrown in hooks aren't caught by our errorHandler.
|
|
53
|
-
|
|
53
|
+
exit();
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
//# sourceMappingURL=ui.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../src/private/node/ui.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../src/private/node/ui.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,UAAU,EAAoB,sBAAsB,EAAC,MAAM,6BAA6B,CAAA;AAC5G,OAAO,EAAC,UAAU,EAAC,MAAM,oCAAoC,CAAA;AAC7D,OAAO,EAAC,QAAQ,EAAC,MAAM,gCAAgC,CAAA;AAEvD,OAAO,EAAM,MAAM,IAAI,SAAS,EAAgB,MAAM,KAAK,CAAA;AAC3D,OAAO,EAAC,YAAY,EAAC,MAAM,QAAQ,CAAA;AAQnC,MAAM,UAAU,UAAU,CACxB,OAAoB,EACpB,EAAC,QAAQ,GAAG,MAAM,EAAE,MAAM,GAAG,UAAU,EAAE,aAAa,EAAoB;IAE1E,MAAM,EAAC,MAAM,EAAE,OAAO,EAAC,GAAG,YAAY,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;IAE9D,IAAI,MAAM,EAAE;QACV,IAAI,UAAU,EAAE;YAAE,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;QAC9C,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,EAAC,WAAW,EAAE,IAAI,EAAC,CAAC,CAAA;KACtE;IAED,OAAO,EAAE,CAAA;IAET,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,OAAoB,EAAE,OAAuB;IAClE,MAAM,EAAC,aAAa,EAAC,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IACnD,OAAO,aAAa,EAAE,CAAA;AACxB,CAAC;AAOD,MAAM,OAAO,MAAO,SAAQ,YAAY;IAMtC,YAAY,OAA0C;QACpD,KAAK,EAAE,CAAA;QAJA,WAAM,GAAa,EAAE,CAAA;QAS9B,UAAK,GAAG,CAAC,KAAa,EAAE,EAAE;YACxB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACvB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAA;QACzB,CAAC,CAAA;QAED,cAAS,GAAG,GAAG,EAAE;YACf,OAAO,IAAI,CAAC,UAAU,CAAA;QACxB,CAAC,CAAA;QAXC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAA;QACpC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAA;IAChC,CAAC;CAUF;AAED,MAAM,YAAY,GAAG,CAAC,OAAqB,EAAE,aAA6B,EAAY,EAAE;IACtF,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAA;IAC1D,8DAA8D;IAC9D,MAAM,MAAM,GAAI,aAAa,EAAE,MAAc,IAAI,IAAI,MAAM,CAAC,EAAC,OAAO,EAAC,CAAC,CAAA;IAEtE,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,EAAE;QAClC,MAAM;QACN,KAAK,EAAE,IAAI;QACX,WAAW,EAAE,KAAK;QAClB,YAAY,EAAE,KAAK;KACpB,CAAC,CAAA;IAEF,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE;QAC1B,OAAO,EAAE,QAAQ,CAAC,OAAO;KAC1B,CAAA;AACH,CAAC,CAAA;AAED,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,GAAQ,EAAE,IAAI,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAClF,IAAI,KAAK,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE;QAC7B,gEAAgE;QAChE,IAAI,EAAE,CAAA;KACP;AACH,CAAC","sourcesContent":["import {collectLog, consoleLog, Logger, LogLevel, outputWhereAppropriate} from '../../public/node/output.js'\nimport {isUnitTest} from '../../public/node/context/local.js'\nimport {treeKill} from '../../public/node/tree-kill.js'\nimport {ReactElement} from 'react'\nimport {Key, render as inkRender, RenderOptions} from 'ink'\nimport {EventEmitter} from 'events'\n\ninterface RenderOnceOptions {\n logLevel?: LogLevel\n logger?: Logger\n renderOptions?: RenderOptions\n}\n\nexport function renderOnce(\n element: JSX.Element,\n {logLevel = 'info', logger = consoleLog, renderOptions}: RenderOnceOptions,\n) {\n const {output, unmount} = renderString(element, renderOptions)\n\n if (output) {\n if (isUnitTest()) collectLog(logLevel, output)\n outputWhereAppropriate(logLevel, logger, output, {skipUIEvent: true})\n }\n\n unmount()\n\n return output\n}\n\nexport function render(element: JSX.Element, options?: RenderOptions) {\n const {waitUntilExit} = inkRender(element, options)\n return waitUntilExit()\n}\n\ninterface Instance {\n output: string | undefined\n unmount: () => void\n}\n\nexport class Stdout extends EventEmitter {\n columns: number\n rows: number\n readonly frames: string[] = []\n private _lastFrame?: string\n\n constructor(options: {columns?: number; rows?: number}) {\n super()\n this.columns = options.columns ?? 80\n this.rows = options.rows ?? 80\n }\n\n write = (frame: string) => {\n this.frames.push(frame)\n this._lastFrame = frame\n }\n\n lastFrame = () => {\n return this._lastFrame\n }\n}\n\nconst renderString = (element: ReactElement, renderOptions?: RenderOptions): Instance => {\n const columns = isUnitTest() ? 80 : process.stdout.columns\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const stdout = (renderOptions?.stdout as any) ?? new Stdout({columns})\n\n const instance = inkRender(element, {\n stdout,\n debug: true,\n exitOnCtrlC: false,\n patchConsole: false,\n })\n\n return {\n output: stdout.lastFrame(),\n unmount: instance.unmount,\n }\n}\n\nexport function handleCtrlC(input: string, key: Key, exit = () => treeKill('SIGINT')) {\n if (input === 'c' && key.ctrl) {\n // Exceptions thrown in hooks aren't caught by our errorHandler.\n exit()\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CLI_KIT_VERSION = "3.48.
|
|
1
|
+
export declare const CLI_KIT_VERSION = "3.48.2";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const CLI_KIT_VERSION = '3.48.
|
|
1
|
+
export const CLI_KIT_VERSION = '3.48.2';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '3.48.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/public/common/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAA","sourcesContent":["export const CLI_KIT_VERSION = '3.48.2'\n"]}
|
|
@@ -2,6 +2,7 @@ import { Command } from '@oclif/core';
|
|
|
2
2
|
import { FlagOutput, Input, ParserOutput, ArgOutput } from '@oclif/core/lib/interfaces/parser.js';
|
|
3
3
|
declare abstract class BaseCommand extends Command {
|
|
4
4
|
static analyticsNameOverride(): string | undefined;
|
|
5
|
+
static analyticsStopCommand(): string | undefined;
|
|
5
6
|
catch(error: Error & {
|
|
6
7
|
exitCode?: number | undefined;
|
|
7
8
|
}): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-command.js","sourceRoot":"","sources":["../../../src/public/node/base-command.ts"],"names":[],"mappings":"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","sourcesContent":["import {errorHandler, registerCleanBugsnagErrorsFromWithinPlugins} from './error-handler.js'\nimport {loadEnvironment} from './environments.js'\nimport {isDevelopment} from './context/local.js'\nimport {addPublicMetadata} from './metadata.js'\nimport {AbortError} from './error.js'\nimport {renderInfo, renderWarning} from './ui.js'\nimport {outputContent, outputInfo, outputToken} from './output.js'\nimport {hashString} from './crypto.js'\nimport {isTruthy} from './context/utilities.js'\nimport {JsonMap} from '../../private/common/json.js'\nimport {underscore} from '../common/string.js'\nimport {Command} from '@oclif/core'\nimport {FlagOutput, Input, ParserOutput, FlagInput, ArgOutput} from '@oclif/core/lib/interfaces/parser.js'\n\ninterface EnvironmentFlags {\n environment?: string\n path?: string\n}\n\nabstract class BaseCommand extends Command {\n public static analyticsNameOverride(): string | undefined {\n return undefined\n }\n\n async catch(error: Error & {exitCode?: number | undefined}): Promise<void> {\n errorHandler(error, this.config)\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected async init(): Promise<any> {\n this.exitWithTimestampWhenEnvVariablePresent()\n if (!isDevelopment()) {\n // This function runs just prior to `run`\n await registerCleanBugsnagErrorsFromWithinPlugins(this.config)\n }\n this.showNpmFlagWarning()\n return super.init()\n }\n\n // NPM creates an environment variable for every flag passed to a script.\n // This function checks for the presence of any of the available CLI flags\n // and warns the user to use the `--` separator.\n protected showNpmFlagWarning(): void {\n const commandVariables = this.constructor as unknown as {_flags: JsonMap}\n const commandFlags = Object.keys(commandVariables._flags || {})\n const possibleNpmEnvVars = commandFlags.map((key) => `npm_config_${underscore(key)}`)\n\n if (possibleNpmEnvVars.some((flag) => process.env[flag])) {\n renderWarning({\n body: [\n 'NPM scripts require an extra',\n {command: '--'},\n 'separator to pass the flags. Example:',\n {command: 'npm run dev -- --reset'},\n ],\n })\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n protected exitWithTimestampWhenEnvVariablePresent() {\n if (isTruthy(process.env.SHOPIFY_CLI_ENV_STARTUP_PERFORMANCE_RUN)) {\n outputInfo(`\n SHOPIFY_CLI_TIMESTAMP_START\n { \"timestamp\": ${Date.now()} }\n SHOPIFY_CLI_TIMESTAMP_END\n `)\n process.exit(0)\n }\n }\n\n protected async parse<\n TFlags extends FlagOutput & {path?: string; verbose?: boolean},\n TGlobalFlags extends FlagOutput,\n TArgs extends ArgOutput,\n >(\n options?: Input<TFlags, TGlobalFlags, TArgs>,\n argv?: string[],\n ): Promise<ParserOutput<TFlags, TGlobalFlags, TArgs> & {argv: string[]}> {\n let result = await super.parse<TFlags, TGlobalFlags, TArgs>(options, argv)\n result = await this.resultWithEnvironment<TFlags, TGlobalFlags, TArgs>(result, options, argv)\n await addFromParsedFlags(result.flags)\n return {...result, ...{argv: result.argv as string[]}}\n }\n\n protected async resultWithEnvironment<\n TFlags extends FlagOutput & {path?: string; verbose?: boolean},\n TGlobalFlags extends FlagOutput,\n TArgs extends ArgOutput,\n >(\n originalResult: ParserOutput<TFlags, TGlobalFlags, TArgs>,\n options?: Input<TFlags, TGlobalFlags, TArgs>,\n argv?: string[],\n ): Promise<ParserOutput<TFlags, TGlobalFlags, TArgs>> {\n // If no environment is specified, don't modify the results\n const flags = originalResult.flags as EnvironmentFlags\n const environmentsFileName = this.environmentsFilename()\n if (!flags.environment || !environmentsFileName) return originalResult\n\n // If the specified environment isn't found, don't modify the results\n const environment = await loadEnvironment(flags.environment, environmentsFileName, {from: flags.path})\n if (!environment) return originalResult\n\n // Parse using noDefaultsOptions to derive a list of flags specified as\n // command-line arguments.\n const noDefaultsResult = await super.parse<TFlags, TGlobalFlags, TArgs>(noDefaultsOptions(options), argv)\n\n // Add the environment's settings to argv and pass them to `super.parse`. This\n // invokes oclif's validation system without breaking the oclif black box.\n // Replace the original result with this one.\n const result = await super.parse<TFlags, TGlobalFlags, TArgs>(options, [\n // Need to specify argv default because we're merging with argsFromEnvironment.\n ...(argv || this.argv),\n ...argsFromEnvironment<TFlags, TGlobalFlags, TArgs>(environment, options, noDefaultsResult),\n ])\n\n // Report successful application of the environment.\n reportEnvironmentApplication<TFlags, TGlobalFlags, TArgs>(\n noDefaultsResult.flags,\n result.flags,\n flags.environment,\n environment,\n )\n\n return result\n }\n\n protected environmentsFilename(): string | undefined {\n // To be re-implemented if needed\n return undefined\n }\n}\n\nexport async function addFromParsedFlags(flags: {path?: string; verbose?: boolean}): Promise<void> {\n await addPublicMetadata(() => ({\n cmd_all_verbose: flags.verbose,\n cmd_all_path_override: flags.path !== undefined,\n cmd_all_path_override_hash: flags.path === undefined ? undefined : hashString(flags.path),\n }))\n}\n\n/**\n * Any flag which is:\n *\n * 1. Present in the final set of flags\n * 2. Specified in the environment\n * 3. Not specified by the user as a command line argument\n *\n * should be reported.\n *\n * It doesn't matter if the environment flag's value was the same as the default; from\n * the user's perspective, they want to know their environment was applied.\n */\nfunction reportEnvironmentApplication<\n TFlags extends FlagOutput,\n TGlobalFlags extends FlagOutput,\n TArgs extends ArgOutput,\n>(\n noDefaultsFlags: ParserOutput<TFlags, TGlobalFlags, TArgs>['flags'],\n flagsWithEnvironments: ParserOutput<TFlags, TGlobalFlags, TArgs>['flags'],\n environmentName: string,\n environment: JsonMap,\n): void {\n const changes: JsonMap = {}\n for (const [name, value] of Object.entries(flagsWithEnvironments)) {\n const userSpecifiedThisFlag = Object.prototype.hasOwnProperty.call(noDefaultsFlags, name)\n const environmentContainsFlag = Object.prototype.hasOwnProperty.call(environment, name)\n if (!userSpecifiedThisFlag && environmentContainsFlag) {\n const valueToReport = name === 'password' ? `********${value.substr(-4)}` : value\n changes[name] = valueToReport\n }\n }\n if (Object.keys(changes).length === 0) return\n\n const items = Object.entries(changes).map(([name, value]) => `${name}: ${value}`)\n renderInfo({\n headline: ['Using applicable flags from', {userInput: environmentName}, 'environment:'],\n body: [{list: {items}}],\n })\n}\n\n/**\n * Strips the defaults from configured flags. For example, if flags contains:\n *\n * ```\n * someFlag: Flags.boolean({\n * description: 'some flag',\n * default: false\n * })\n * ```\n *\n * it becomes:\n *\n * ```\n * someFlag: Flags.boolean({\n * description: 'some flag'\n * })\n * ```\n *\n * If we parse using this configuration, the only specified flags will be those\n * the user actually passed on the command line.\n */\nfunction noDefaultsOptions<TFlags extends FlagOutput, TGlobalFlags extends FlagOutput, TArgs extends ArgOutput>(\n options: Input<TFlags, TGlobalFlags, TArgs> | undefined,\n): Input<TFlags, TGlobalFlags, TArgs> | undefined {\n if (!options?.flags) return options\n return {\n ...options,\n flags: Object.fromEntries(\n Object.entries(options.flags).map(([label, settings]) => {\n const copiedSettings = {...(settings as {default?: unknown})}\n delete copiedSettings.default\n return [label, copiedSettings]\n }),\n ) as FlagInput<TFlags>,\n }\n}\n\n/**\n * Converts the environment's settings to arguments as though passed on the command\n * line, skipping any arguments the user specified on the command line.\n */\nfunction argsFromEnvironment<TFlags extends FlagOutput, TGlobalFlags extends FlagOutput, TArgs extends ArgOutput>(\n environment: JsonMap,\n options: Input<TFlags, TGlobalFlags, TArgs> | undefined,\n noDefaultsResult: ParserOutput<TFlags, TArgs>,\n): string[] {\n const args: string[] = []\n for (const [label, value] of Object.entries(environment)) {\n const flagIsRelevantToCommand = options?.flags && Object.prototype.hasOwnProperty.call(options.flags, label)\n const userSpecifiedThisFlag =\n noDefaultsResult.flags && Object.prototype.hasOwnProperty.call(noDefaultsResult.flags, label)\n if (flagIsRelevantToCommand && !userSpecifiedThisFlag) {\n if (typeof value === 'boolean') {\n if (value === true) {\n args.push(`--${label}`)\n } else {\n throw new AbortError(\n outputContent`Environments can only specify true for boolean flags. Attempted to set ${outputToken.yellow(\n label,\n )} to false.`,\n )\n }\n } else if (Array.isArray(value)) {\n value.forEach((element) => args.push(`--${label}`, `${element}`))\n } else {\n args.push(`--${label}`, `${value}`)\n }\n }\n }\n return args\n}\n\nexport default BaseCommand\n"]}
|
|
1
|
+
{"version":3,"file":"base-command.js","sourceRoot":"","sources":["../../../src/public/node/base-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,2CAA2C,EAAC,MAAM,oBAAoB,CAAA;AAC5F,OAAO,EAAC,eAAe,EAAC,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAC,iBAAiB,EAAC,MAAM,eAAe,CAAA;AAC/C,OAAO,EAAC,UAAU,EAAC,MAAM,YAAY,CAAA;AACrC,OAAO,EAAC,UAAU,EAAE,aAAa,EAAC,MAAM,SAAS,CAAA;AACjD,OAAO,EAAC,aAAa,EAAE,UAAU,EAAE,WAAW,EAAC,MAAM,aAAa,CAAA;AAClE,OAAO,EAAC,UAAU,EAAC,MAAM,aAAa,CAAA;AACtC,OAAO,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAA;AAE/C,OAAO,EAAC,UAAU,EAAC,MAAM,qBAAqB,CAAA;AAC9C,OAAO,EAAC,OAAO,EAAC,MAAM,aAAa,CAAA;AAQnC,MAAe,WAAY,SAAQ,OAAO;IACjC,MAAM,CAAC,qBAAqB;QACjC,OAAO,SAAS,CAAA;IAClB,CAAC;IAEM,MAAM,CAAC,oBAAoB;QAChC,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAA8C;QACxD,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;IAED,8DAA8D;IACpD,KAAK,CAAC,IAAI;QAClB,IAAI,CAAC,uCAAuC,EAAE,CAAA;QAC9C,IAAI,CAAC,aAAa,EAAE,EAAE;YACpB,yCAAyC;YACzC,MAAM,2CAA2C,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;SAC/D;QACD,IAAI,CAAC,kBAAkB,EAAE,CAAA;QACzB,OAAO,KAAK,CAAC,IAAI,EAAE,CAAA;IACrB,CAAC;IAED,yEAAyE;IACzE,0EAA0E;IAC1E,gDAAgD;IACtC,kBAAkB;QAC1B,MAAM,gBAAgB,GAAG,IAAI,CAAC,WAA2C,CAAA;QACzE,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,IAAI,EAAE,CAAC,CAAA;QAC/D,MAAM,kBAAkB,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,cAAc,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QAErF,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE;YACxD,aAAa,CAAC;gBACZ,IAAI,EAAE;oBACJ,8BAA8B;oBAC9B,EAAC,OAAO,EAAE,IAAI,EAAC;oBACf,uCAAuC;oBACvC,EAAC,OAAO,EAAE,wBAAwB,EAAC;iBACpC;aACF,CAAC,CAAA;SACH;IACH,CAAC;IAED,6EAA6E;IACnE,uCAAuC;QAC/C,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,EAAE;YACjE,UAAU,CAAC;;uBAEM,IAAI,CAAC,GAAG,EAAE;;OAE1B,CAAC,CAAA;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;SAChB;IACH,CAAC;IAES,KAAK,CAAC,KAAK,CAKnB,OAA4C,EAC5C,IAAe;QAEf,IAAI,MAAM,GAAG,MAAM,KAAK,CAAC,KAAK,CAA8B,OAAO,EAAE,IAAI,CAAC,CAAA;QAC1E,MAAM,GAAG,MAAM,IAAI,CAAC,qBAAqB,CAA8B,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;QAC7F,MAAM,kBAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACtC,OAAO,EAAC,GAAG,MAAM,EAAE,GAAG,EAAC,IAAI,EAAE,MAAM,CAAC,IAAgB,EAAC,EAAC,CAAA;IACxD,CAAC;IAES,KAAK,CAAC,qBAAqB,CAKnC,cAAyD,EACzD,OAA4C,EAC5C,IAAe;QAEf,2DAA2D;QAC3D,MAAM,KAAK,GAAG,cAAc,CAAC,KAAyB,CAAA;QACtD,MAAM,oBAAoB,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAA;QACxD,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,oBAAoB;YAAE,OAAO,cAAc,CAAA;QAEtE,qEAAqE;QACrE,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,WAAW,EAAE,oBAAoB,EAAE,EAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAC,CAAC,CAAA;QACtG,IAAI,CAAC,WAAW;YAAE,OAAO,cAAc,CAAA;QAEvC,uEAAuE;QACvE,0BAA0B;QAC1B,MAAM,gBAAgB,GAAG,MAAM,KAAK,CAAC,KAAK,CAA8B,iBAAiB,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAA;QAEzG,8EAA8E;QAC9E,0EAA0E;QAC1E,6CAA6C;QAC7C,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,KAAK,CAA8B,OAAO,EAAE;YACrE,+EAA+E;YAC/E,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC;YACtB,GAAG,mBAAmB,CAA8B,WAAW,EAAE,OAAO,EAAE,gBAAgB,CAAC;SAC5F,CAAC,CAAA;QAEF,oDAAoD;QACpD,4BAA4B,CAC1B,gBAAgB,CAAC,KAAK,EACtB,MAAM,CAAC,KAAK,EACZ,KAAK,CAAC,WAAW,EACjB,WAAW,CACZ,CAAA;QAED,OAAO,MAAM,CAAA;IACf,CAAC;IAES,oBAAoB;QAC5B,iCAAiC;QACjC,OAAO,SAAS,CAAA;IAClB,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAAyC;IAChF,MAAM,iBAAiB,CAAC,GAAG,EAAE,CAAC,CAAC;QAC7B,eAAe,EAAE,KAAK,CAAC,OAAO;QAC9B,qBAAqB,EAAE,KAAK,CAAC,IAAI,KAAK,SAAS;QAC/C,0BAA0B,EAAE,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;KAC1F,CAAC,CAAC,CAAA;AACL,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,4BAA4B,CAKnC,eAAmE,EACnE,qBAAyE,EACzE,eAAuB,EACvB,WAAoB;IAEpB,MAAM,OAAO,GAAY,EAAE,CAAA;IAC3B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,qBAAqB,CAAC,EAAE;QACjE,MAAM,qBAAqB,GAAG,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAA;QACzF,MAAM,uBAAuB,GAAG,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;QACvF,IAAI,CAAC,qBAAqB,IAAI,uBAAuB,EAAE;YACrD,MAAM,aAAa,GAAG,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,WAAW,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAA;YACjF,OAAO,CAAC,IAAI,CAAC,GAAG,aAAa,CAAA;SAC9B;KACF;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAM;IAE7C,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,KAAK,KAAK,EAAE,CAAC,CAAA;IACjF,UAAU,CAAC;QACT,QAAQ,EAAE,CAAC,6BAA6B,EAAE,EAAC,SAAS,EAAE,eAAe,EAAC,EAAE,cAAc,CAAC;QACvF,IAAI,EAAE,CAAC,EAAC,IAAI,EAAE,EAAC,KAAK,EAAC,EAAC,CAAC;KACxB,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAS,iBAAiB,CACxB,OAAuD;IAEvD,IAAI,CAAC,OAAO,EAAE,KAAK;QAAE,OAAO,OAAO,CAAA;IACnC,OAAO;QACL,GAAG,OAAO;QACV,KAAK,EAAE,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,EAAE;YACtD,MAAM,cAAc,GAAG,EAAC,GAAI,QAAgC,EAAC,CAAA;YAC7D,OAAO,cAAc,CAAC,OAAO,CAAA;YAC7B,OAAO,CAAC,KAAK,EAAE,cAAc,CAAC,CAAA;QAChC,CAAC,CAAC,CACkB;KACvB,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAC1B,WAAoB,EACpB,OAAuD,EACvD,gBAA6C;IAE7C,MAAM,IAAI,GAAa,EAAE,CAAA;IACzB,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;QACxD,MAAM,uBAAuB,GAAG,OAAO,EAAE,KAAK,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;QAC5G,MAAM,qBAAqB,GACzB,gBAAgB,CAAC,KAAK,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;QAC/F,IAAI,uBAAuB,IAAI,CAAC,qBAAqB,EAAE;YACrD,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE;gBAC9B,IAAI,KAAK,KAAK,IAAI,EAAE;oBAClB,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC,CAAA;iBACxB;qBAAM;oBACL,MAAM,IAAI,UAAU,CAClB,aAAa,CAAA,0EAA0E,WAAW,CAAC,MAAM,CACvG,KAAK,CACN,YAAY,CACd,CAAA;iBACF;aACF;iBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;gBAC/B,KAAK,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAA;aAClE;iBAAM;gBACL,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC,CAAA;aACpC;SACF;KACF;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,eAAe,WAAW,CAAA","sourcesContent":["import {errorHandler, registerCleanBugsnagErrorsFromWithinPlugins} from './error-handler.js'\nimport {loadEnvironment} from './environments.js'\nimport {isDevelopment} from './context/local.js'\nimport {addPublicMetadata} from './metadata.js'\nimport {AbortError} from './error.js'\nimport {renderInfo, renderWarning} from './ui.js'\nimport {outputContent, outputInfo, outputToken} from './output.js'\nimport {hashString} from './crypto.js'\nimport {isTruthy} from './context/utilities.js'\nimport {JsonMap} from '../../private/common/json.js'\nimport {underscore} from '../common/string.js'\nimport {Command} from '@oclif/core'\nimport {FlagOutput, Input, ParserOutput, FlagInput, ArgOutput} from '@oclif/core/lib/interfaces/parser.js'\n\ninterface EnvironmentFlags {\n environment?: string\n path?: string\n}\n\nabstract class BaseCommand extends Command {\n public static analyticsNameOverride(): string | undefined {\n return undefined\n }\n\n public static analyticsStopCommand(): string | undefined {\n return undefined\n }\n\n async catch(error: Error & {exitCode?: number | undefined}): Promise<void> {\n errorHandler(error, this.config)\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected async init(): Promise<any> {\n this.exitWithTimestampWhenEnvVariablePresent()\n if (!isDevelopment()) {\n // This function runs just prior to `run`\n await registerCleanBugsnagErrorsFromWithinPlugins(this.config)\n }\n this.showNpmFlagWarning()\n return super.init()\n }\n\n // NPM creates an environment variable for every flag passed to a script.\n // This function checks for the presence of any of the available CLI flags\n // and warns the user to use the `--` separator.\n protected showNpmFlagWarning(): void {\n const commandVariables = this.constructor as unknown as {_flags: JsonMap}\n const commandFlags = Object.keys(commandVariables._flags || {})\n const possibleNpmEnvVars = commandFlags.map((key) => `npm_config_${underscore(key)}`)\n\n if (possibleNpmEnvVars.some((flag) => process.env[flag])) {\n renderWarning({\n body: [\n 'NPM scripts require an extra',\n {command: '--'},\n 'separator to pass the flags. Example:',\n {command: 'npm run dev -- --reset'},\n ],\n })\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\n protected exitWithTimestampWhenEnvVariablePresent() {\n if (isTruthy(process.env.SHOPIFY_CLI_ENV_STARTUP_PERFORMANCE_RUN)) {\n outputInfo(`\n SHOPIFY_CLI_TIMESTAMP_START\n { \"timestamp\": ${Date.now()} }\n SHOPIFY_CLI_TIMESTAMP_END\n `)\n process.exit(0)\n }\n }\n\n protected async parse<\n TFlags extends FlagOutput & {path?: string; verbose?: boolean},\n TGlobalFlags extends FlagOutput,\n TArgs extends ArgOutput,\n >(\n options?: Input<TFlags, TGlobalFlags, TArgs>,\n argv?: string[],\n ): Promise<ParserOutput<TFlags, TGlobalFlags, TArgs> & {argv: string[]}> {\n let result = await super.parse<TFlags, TGlobalFlags, TArgs>(options, argv)\n result = await this.resultWithEnvironment<TFlags, TGlobalFlags, TArgs>(result, options, argv)\n await addFromParsedFlags(result.flags)\n return {...result, ...{argv: result.argv as string[]}}\n }\n\n protected async resultWithEnvironment<\n TFlags extends FlagOutput & {path?: string; verbose?: boolean},\n TGlobalFlags extends FlagOutput,\n TArgs extends ArgOutput,\n >(\n originalResult: ParserOutput<TFlags, TGlobalFlags, TArgs>,\n options?: Input<TFlags, TGlobalFlags, TArgs>,\n argv?: string[],\n ): Promise<ParserOutput<TFlags, TGlobalFlags, TArgs>> {\n // If no environment is specified, don't modify the results\n const flags = originalResult.flags as EnvironmentFlags\n const environmentsFileName = this.environmentsFilename()\n if (!flags.environment || !environmentsFileName) return originalResult\n\n // If the specified environment isn't found, don't modify the results\n const environment = await loadEnvironment(flags.environment, environmentsFileName, {from: flags.path})\n if (!environment) return originalResult\n\n // Parse using noDefaultsOptions to derive a list of flags specified as\n // command-line arguments.\n const noDefaultsResult = await super.parse<TFlags, TGlobalFlags, TArgs>(noDefaultsOptions(options), argv)\n\n // Add the environment's settings to argv and pass them to `super.parse`. This\n // invokes oclif's validation system without breaking the oclif black box.\n // Replace the original result with this one.\n const result = await super.parse<TFlags, TGlobalFlags, TArgs>(options, [\n // Need to specify argv default because we're merging with argsFromEnvironment.\n ...(argv || this.argv),\n ...argsFromEnvironment<TFlags, TGlobalFlags, TArgs>(environment, options, noDefaultsResult),\n ])\n\n // Report successful application of the environment.\n reportEnvironmentApplication<TFlags, TGlobalFlags, TArgs>(\n noDefaultsResult.flags,\n result.flags,\n flags.environment,\n environment,\n )\n\n return result\n }\n\n protected environmentsFilename(): string | undefined {\n // To be re-implemented if needed\n return undefined\n }\n}\n\nexport async function addFromParsedFlags(flags: {path?: string; verbose?: boolean}): Promise<void> {\n await addPublicMetadata(() => ({\n cmd_all_verbose: flags.verbose,\n cmd_all_path_override: flags.path !== undefined,\n cmd_all_path_override_hash: flags.path === undefined ? undefined : hashString(flags.path),\n }))\n}\n\n/**\n * Any flag which is:\n *\n * 1. Present in the final set of flags\n * 2. Specified in the environment\n * 3. Not specified by the user as a command line argument\n *\n * should be reported.\n *\n * It doesn't matter if the environment flag's value was the same as the default; from\n * the user's perspective, they want to know their environment was applied.\n */\nfunction reportEnvironmentApplication<\n TFlags extends FlagOutput,\n TGlobalFlags extends FlagOutput,\n TArgs extends ArgOutput,\n>(\n noDefaultsFlags: ParserOutput<TFlags, TGlobalFlags, TArgs>['flags'],\n flagsWithEnvironments: ParserOutput<TFlags, TGlobalFlags, TArgs>['flags'],\n environmentName: string,\n environment: JsonMap,\n): void {\n const changes: JsonMap = {}\n for (const [name, value] of Object.entries(flagsWithEnvironments)) {\n const userSpecifiedThisFlag = Object.prototype.hasOwnProperty.call(noDefaultsFlags, name)\n const environmentContainsFlag = Object.prototype.hasOwnProperty.call(environment, name)\n if (!userSpecifiedThisFlag && environmentContainsFlag) {\n const valueToReport = name === 'password' ? `********${value.substr(-4)}` : value\n changes[name] = valueToReport\n }\n }\n if (Object.keys(changes).length === 0) return\n\n const items = Object.entries(changes).map(([name, value]) => `${name}: ${value}`)\n renderInfo({\n headline: ['Using applicable flags from', {userInput: environmentName}, 'environment:'],\n body: [{list: {items}}],\n })\n}\n\n/**\n * Strips the defaults from configured flags. For example, if flags contains:\n *\n * ```\n * someFlag: Flags.boolean({\n * description: 'some flag',\n * default: false\n * })\n * ```\n *\n * it becomes:\n *\n * ```\n * someFlag: Flags.boolean({\n * description: 'some flag'\n * })\n * ```\n *\n * If we parse using this configuration, the only specified flags will be those\n * the user actually passed on the command line.\n */\nfunction noDefaultsOptions<TFlags extends FlagOutput, TGlobalFlags extends FlagOutput, TArgs extends ArgOutput>(\n options: Input<TFlags, TGlobalFlags, TArgs> | undefined,\n): Input<TFlags, TGlobalFlags, TArgs> | undefined {\n if (!options?.flags) return options\n return {\n ...options,\n flags: Object.fromEntries(\n Object.entries(options.flags).map(([label, settings]) => {\n const copiedSettings = {...(settings as {default?: unknown})}\n delete copiedSettings.default\n return [label, copiedSettings]\n }),\n ) as FlagInput<TFlags>,\n }\n}\n\n/**\n * Converts the environment's settings to arguments as though passed on the command\n * line, skipping any arguments the user specified on the command line.\n */\nfunction argsFromEnvironment<TFlags extends FlagOutput, TGlobalFlags extends FlagOutput, TArgs extends ArgOutput>(\n environment: JsonMap,\n options: Input<TFlags, TGlobalFlags, TArgs> | undefined,\n noDefaultsResult: ParserOutput<TFlags, TArgs>,\n): string[] {\n const args: string[] = []\n for (const [label, value] of Object.entries(environment)) {\n const flagIsRelevantToCommand = options?.flags && Object.prototype.hasOwnProperty.call(options.flags, label)\n const userSpecifiedThisFlag =\n noDefaultsResult.flags && Object.prototype.hasOwnProperty.call(noDefaultsResult.flags, label)\n if (flagIsRelevantToCommand && !userSpecifiedThisFlag) {\n if (typeof value === 'boolean') {\n if (value === true) {\n args.push(`--${label}`)\n } else {\n throw new AbortError(\n outputContent`Environments can only specify true for boolean flags. Attempted to set ${outputToken.yellow(\n label,\n )} to false.`,\n )\n }\n } else if (Array.isArray(value)) {\n value.forEach((element) => args.push(`--${label}`, `${element}`))\n } else {\n args.push(`--${label}`, `${value}`)\n }\n }\n }\n return args\n}\n\nexport default BaseCommand\n"]}
|