@shopify/cli-kit 3.31.0 → 3.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/environment/local.d.ts +1 -0
- package/dist/environment/local.js +4 -1
- package/dist/environment/local.js.map +1 -1
- package/dist/file.d.ts +10 -3
- package/dist/file.js +36 -36
- package/dist/file.js.map +1 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -3
- package/dist/index.js.map +1 -1
- package/dist/metadata.d.ts +1 -1
- package/dist/metadata.js.map +1 -1
- package/dist/monorail.d.ts +1 -1
- package/dist/monorail.js.map +1 -1
- package/dist/os.d.ts +4 -3
- package/dist/os.js +3 -4
- package/dist/os.js.map +1 -1
- package/dist/output.d.ts +2 -2
- package/dist/output.js +1 -1
- package/dist/output.js.map +1 -1
- package/dist/path.d.ts +5 -5
- package/dist/path.js +6 -7
- package/dist/path.js.map +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js.map +1 -1
- package/dist/{json.d.ts → private/common/json.d.ts} +0 -0
- package/dist/{json.js → private/common/json.js} +0 -0
- package/dist/private/common/json.js.map +1 -0
- package/dist/private/node/analytics.d.ts +27 -0
- package/dist/private/node/analytics.js +57 -0
- package/dist/private/node/analytics.js.map +1 -0
- package/dist/private/node/ui/components/Alert.test.js +5 -5
- package/dist/private/node/ui/components/Alert.test.js.map +1 -1
- package/dist/private/node/ui/components/Banner.js +5 -5
- package/dist/private/node/ui/components/Banner.js.map +1 -1
- package/dist/private/node/ui/components/Banner.test.js +11 -11
- package/dist/private/node/ui/components/Banner.test.js.map +1 -1
- package/dist/private/node/ui/components/Command.test.js +3 -3
- package/dist/private/node/ui/components/Command.test.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.d.ts +2 -2
- package/dist/private/node/ui/components/ConcurrentOutput.js +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
- package/dist/private/node/ui/components/ConcurrentOutput.test.js +3 -3
- package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
- package/dist/private/node/ui/components/FatalError.test.js +9 -9
- package/dist/private/node/ui/components/FatalError.test.js.map +1 -1
- package/dist/private/node/ui/components/FilePath.test.js +3 -3
- package/dist/private/node/ui/components/FilePath.test.js.map +1 -1
- package/dist/private/node/ui/components/Link.test.js +5 -5
- package/dist/private/node/ui/components/Link.test.js.map +1 -1
- package/dist/private/node/ui/components/List.test.js +5 -5
- package/dist/private/node/ui/components/List.test.js.map +1 -1
- package/dist/private/node/ui/components/SelectInput.d.ts +2 -2
- package/dist/private/node/ui/components/SelectInput.js +16 -24
- package/dist/private/node/ui/components/SelectInput.js.map +1 -1
- package/dist/private/node/ui/components/SelectInput.test.js +62 -32
- package/dist/private/node/ui/components/SelectInput.test.js.map +1 -1
- package/dist/private/node/ui/components/{Prompt.d.ts → SelectPrompt.d.ts} +4 -3
- package/dist/private/node/ui/components/SelectPrompt.js +34 -0
- package/dist/private/node/ui/components/SelectPrompt.js.map +1 -0
- package/dist/private/node/ui/components/{Prompt.test.d.ts → SelectPrompt.test.d.ts} +0 -0
- package/dist/private/node/ui/components/{Prompt.test.js → SelectPrompt.test.js} +7 -6
- package/dist/private/node/ui/components/SelectPrompt.test.js.map +1 -0
- package/dist/private/node/ui/components/Table.js +1 -1
- package/dist/private/node/ui/components/Table.js.map +1 -1
- package/dist/private/node/ui/components/Tasks.d.ts +1 -1
- package/dist/private/node/ui/components/Tasks.js +3 -3
- package/dist/private/node/ui/components/Tasks.js.map +1 -1
- package/dist/private/node/ui/components/Tasks.test.js +4 -4
- package/dist/private/node/ui/components/Tasks.test.js.map +1 -1
- package/dist/private/node/ui/components/TextAnimation.js.map +1 -1
- package/dist/private/node/ui/components/TextInput.d.ts +9 -0
- package/dist/private/node/ui/components/TextInput.js +74 -0
- package/dist/private/node/ui/components/TextInput.js.map +1 -0
- package/dist/private/node/ui/components/TextInput.test.d.ts +1 -0
- package/dist/private/node/ui/components/TextInput.test.js +139 -0
- package/dist/private/node/ui/components/TextInput.test.js.map +1 -0
- package/dist/private/node/ui/components/TextPrompt.d.ts +8 -0
- package/dist/private/node/ui/components/TextPrompt.js +52 -0
- package/dist/private/node/ui/components/TextPrompt.js.map +1 -0
- package/dist/private/node/ui/components/TextPrompt.test.d.ts +1 -0
- package/dist/private/node/ui/components/TextPrompt.test.js +68 -0
- package/dist/private/node/ui/components/TextPrompt.test.js.map +1 -0
- package/dist/private/node/ui/components/TokenizedText.test.js +3 -3
- package/dist/private/node/ui/components/TokenizedText.test.js.map +1 -1
- package/dist/private/node/ui/components/UserInput.test.js +3 -3
- package/dist/private/node/ui/components/UserInput.test.js.map +1 -1
- package/dist/private/node/ui/hooks/use-layout.d.ts +6 -3
- package/dist/private/node/ui/hooks/use-layout.js +17 -8
- package/dist/private/node/ui/hooks/use-layout.js.map +1 -1
- package/dist/private/node/ui.d.ts +2 -3
- package/dist/private/node/ui.js +7 -16
- package/dist/private/node/ui.js.map +1 -1
- package/dist/public/common/array.js +1 -1
- package/dist/public/common/array.js.map +1 -1
- package/dist/public/common/collection.js +1 -1
- package/dist/public/common/collection.js.map +1 -1
- package/dist/public/common/function.js +1 -1
- package/dist/public/common/function.js.map +1 -1
- package/dist/public/common/lang.js +1 -1
- package/dist/public/common/lang.js.map +1 -1
- package/dist/public/common/object.js +1 -1
- package/dist/public/common/object.js.map +1 -1
- package/dist/public/common/url.d.ts +7 -0
- package/dist/public/common/url.js +17 -0
- package/dist/public/common/url.js.map +1 -0
- package/dist/public/node/abort.d.ts +16 -0
- package/dist/public/node/abort.js +17 -0
- package/dist/public/node/abort.js.map +1 -0
- package/dist/public/node/analytics.d.ts +13 -0
- package/dist/public/node/analytics.js +82 -0
- package/dist/public/node/analytics.js.map +1 -0
- package/dist/public/node/archiver.js +1 -1
- package/dist/public/node/archiver.js.map +1 -1
- package/dist/public/node/base-command.js.map +1 -1
- package/dist/public/node/error-handler.js +3 -2
- package/dist/public/node/error-handler.js.map +1 -1
- package/dist/public/node/framework.js +1 -1
- package/dist/public/node/framework.js.map +1 -1
- package/dist/public/node/hooks/postrun.js +2 -2
- package/dist/public/node/hooks/postrun.js.map +1 -1
- package/dist/public/node/hooks/prerun.js +2 -2
- package/dist/public/node/hooks/prerun.js.map +1 -1
- package/dist/public/node/node-package-manager.d.ts +3 -3
- package/dist/public/node/node-package-manager.js +1 -1
- package/dist/public/node/node-package-manager.js.map +1 -1
- package/dist/public/node/presets.d.ts +1 -1
- package/dist/public/node/presets.js.map +1 -1
- package/dist/public/node/ruby.d.ts +2 -2
- package/dist/public/node/ruby.js +2 -2
- package/dist/public/node/ruby.js.map +1 -1
- package/dist/public/node/ui.d.ts +12 -17
- package/dist/public/node/ui.js +25 -29
- package/dist/public/node/ui.js.map +1 -1
- package/dist/session/authorize.js +1 -1
- package/dist/session/authorize.js.map +1 -1
- package/dist/session/redirect-listener.js +6 -3
- package/dist/session/redirect-listener.js.map +1 -1
- package/dist/system.d.ts +2 -2
- package/dist/system.js.map +1 -1
- package/dist/testing/ui.d.ts +1 -1
- package/dist/testing/ui.js +1 -1
- package/dist/testing/ui.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/ui/inquirer/autocomplete.d.ts +2 -2
- package/dist/ui/inquirer/autocomplete.js.map +1 -1
- package/dist/ui/inquirer/input.d.ts +2 -2
- package/dist/ui/inquirer/input.js.map +1 -1
- package/dist/ui/inquirer/password.d.ts +2 -2
- package/dist/ui/inquirer/password.js.map +1 -1
- package/dist/ui/inquirer/select.d.ts +2 -2
- package/dist/ui/inquirer/select.js +2 -2
- package/dist/ui/inquirer/select.js.map +1 -1
- package/package.json +30 -28
- package/dist/abort.d.ts +0 -1
- package/dist/abort.js +0 -2
- package/dist/abort.js.map +0 -1
- package/dist/analytics.d.ts +0 -44
- package/dist/analytics.js +0 -154
- package/dist/analytics.js.map +0 -1
- package/dist/id.d.ts +0 -6
- package/dist/id.js +0 -18
- package/dist/id.js.map +0 -1
- package/dist/json.js.map +0 -1
- package/dist/private/node/ui/components/Prompt.js +0 -23
- package/dist/private/node/ui/components/Prompt.js.map +0 -1
- package/dist/private/node/ui/components/Prompt.test.js.map +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Command } from './Command.js';
|
|
2
|
-
import { renderString } from '../../ui.js';
|
|
3
2
|
import { describe, expect, test } from 'vitest';
|
|
4
3
|
import React from 'react';
|
|
4
|
+
import { render } from 'ink-testing-library';
|
|
5
5
|
describe('Command', async () => {
|
|
6
6
|
test('renders correctly', async () => {
|
|
7
|
-
const {
|
|
8
|
-
expect(
|
|
7
|
+
const { lastFrame } = render(React.createElement(Command, { command: "npm install" }));
|
|
8
|
+
expect(lastFrame()).toMatchInlineSnapshot('"`npm install`"');
|
|
9
9
|
});
|
|
10
10
|
});
|
|
11
11
|
//# sourceMappingURL=Command.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Command.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Command.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAA;AACpC,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"Command.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Command.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAA;AACpC,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAA;AAE1C,QAAQ,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;IAC7B,IAAI,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,OAAO,IAAC,OAAO,EAAC,aAAa,GAAG,CAAC,CAAA;QAE7D,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,qBAAqB,CAAC,iBAAiB,CAAC,CAAA;IAC9D,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {Command} from './Command.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\nimport {render} from 'ink-testing-library'\n\ndescribe('Command', async () => {\n test('renders correctly', async () => {\n const {lastFrame} = render(<Command command=\"npm install\" />)\n\n expect(lastFrame()).toMatchInlineSnapshot('\"`npm install`\"')\n })\n})\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { OutputProcess } from '../../../../output.js';
|
|
3
|
+
import { AbortController } from '../../../../public/node/abort.js';
|
|
3
4
|
import { FunctionComponent } from 'react';
|
|
4
|
-
import
|
|
5
|
-
import { Writable } from 'node:stream';
|
|
5
|
+
import { Writable } from 'stream';
|
|
6
6
|
export declare type WritableStream = (process: OutputProcess, index: number) => Writable;
|
|
7
7
|
interface Props {
|
|
8
8
|
processes: OutputProcess[];
|
|
@@ -2,7 +2,7 @@ import useAsyncAndUnmount from '../hooks/use-async-and-unmount.js';
|
|
|
2
2
|
import React, { useState } from 'react';
|
|
3
3
|
import { Box, Static, Text } from 'ink';
|
|
4
4
|
import stripAnsi from 'strip-ansi';
|
|
5
|
-
import { Writable } from '
|
|
5
|
+
import { Writable } from 'stream';
|
|
6
6
|
/**
|
|
7
7
|
* Renders output from concurrent processes to the terminal.
|
|
8
8
|
* Output will be divided in a three column layout
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConcurrentOutput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.tsx"],"names":[],"mappings":"AACA,OAAO,kBAAkB,MAAM,mCAAmC,CAAA;
|
|
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 '../../../../output.js'\nimport useAsyncAndUnmount from '../hooks/use-async-and-unmount.js'\nimport {AbortController} from '../../../../public/node/abort.js'\nimport React, {FunctionComponent, useState} from 'react'\nimport {Box, Static, Text} from 'ink'\nimport stripAnsi from 'strip-ansi'\nimport {Writable} from 'stream'\n\nexport type WritableStream = (process: OutputProcess, index: number) => Writable\n\ninterface Props {\n processes: OutputProcess[]\n abortController: AbortController\n showTimestamps?: boolean\n}\ninterface Chunk {\n color: string\n prefix: string\n lines: string[]\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 | [nodemon] 2.0.19\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<Props> = ({processes, abortController, showTimestamps = true}) => {\n const [processOutput, setProcessOutput] = useState<Chunk[]>([])\n const concurrentColors = ['yellow', 'cyan', 'magenta', 'green', 'blue']\n const prefixColumnSize = Math.max(...processes.map((process) => process.prefix.length))\n\n function lineColor(index: number) {\n const colorIndex = index < concurrentColors.length ? index : index % concurrentColors.length\n return concurrentColors[colorIndex]!\n }\n\n const writableStream = (process: OutputProcess, index: number) => {\n return new Writable({\n write(chunk, _encoding, next) {\n const lines = stripAnsi(chunk.toString('ascii').replace(/(\\n)$/, '')).split(/\\n/)\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\n const runProcesses = () => {\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, abortController.signal)\n }),\n )\n }\n\n useAsyncAndUnmount(runProcesses, {onRejected: () => abortController.abort()})\n\n return (\n <Static items={processOutput}>\n {(chunk, index) => {\n return (\n <Box flexDirection=\"column\" key={index}>\n {chunk.lines.map((line, index) => (\n <Box key={index} flexDirection=\"row\">\n {showTimestamps && (\n <Box>\n <Box marginRight={1}>\n <Text color={chunk.color}>{new Date().toISOString().replace(/T/, ' ').replace(/\\..+/, '')}</Text>\n </Box>\n\n <Text bold color={chunk.color}>\n |\n </Text>\n </Box>\n )}\n\n <Box width={prefixColumnSize} marginX={1}>\n <Text color={chunk.color}>{chunk.prefix}</Text>\n </Box>\n\n <Text bold color={chunk.color}>\n |\n </Text>\n\n <Box flexGrow={1} paddingLeft={1}>\n <Text color={chunk.color}>{line}</Text>\n </Box>\n </Box>\n ))}\n </Box>\n )\n }}\n </Static>\n )\n}\n\nexport default ConcurrentOutput\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import ConcurrentOutput from './ConcurrentOutput.js';
|
|
2
2
|
import { unstyled } from '../../../../output.js';
|
|
3
|
-
import {
|
|
3
|
+
import { getLastFrameAfterUnmount } from '../../../../testing/ui.js';
|
|
4
|
+
import { AbortController } from '../../../../public/node/abort.js';
|
|
4
5
|
import React from 'react';
|
|
5
6
|
import { describe, expect, test } from 'vitest';
|
|
6
|
-
import { AbortController } from 'abort-controller';
|
|
7
7
|
import { render } from 'ink-testing-library';
|
|
8
8
|
describe('ConcurrentOutput', () => {
|
|
9
9
|
test('renders a stream of concurrent outputs from sub-processes', async () => {
|
|
@@ -40,7 +40,7 @@ describe('ConcurrentOutput', () => {
|
|
|
40
40
|
// wait for all output to be rendered
|
|
41
41
|
await frontendPromise;
|
|
42
42
|
// Then
|
|
43
|
-
expect(unstyled(
|
|
43
|
+
expect(unstyled(getLastFrameAfterUnmount(renderInstance)).replace(/\d/g, '0')).toMatchInlineSnapshot(`
|
|
44
44
|
"0000-00-00 00:00:00 | backend | first backend message
|
|
45
45
|
0000-00-00 00:00:00 | backend | second backend message
|
|
46
46
|
0000-00-00 00:00:00 | backend | third backend message
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConcurrentOutput.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.test.tsx"],"names":[],"mappings":"AAAA,OAAO,gBAAgB,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"ConcurrentOutput.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/ConcurrentOutput.test.tsx"],"names":[],"mappings":"AAAA,OAAO,gBAAgB,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAA;AAC9C,OAAO,EAAC,wBAAwB,EAAC,MAAM,2BAA2B,CAAA;AAClE,OAAO,EAAC,eAAe,EAAc,MAAM,kCAAkC,CAAA;AAC7E,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAA;AAG1C,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;YAC1B,CAAC;SACF,CAAA;QACD,OAAO;QAEP,MAAM,cAAc,GAAG,MAAM,CAC3B,oBAAC,gBAAgB,IAAC,SAAS,EAAE,CAAC,cAAc,EAAE,eAAe,CAAC,EAAE,eAAe,EAAE,IAAI,eAAe,EAAE,GAAI,CAC3G,CAAA;QAED,qCAAqC;QACrC,MAAM,eAAe,CAAA;QAErB,OAAO;QACP,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAC,cAAc,CAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;KAQrG,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import ConcurrentOutput from './ConcurrentOutput.js'\nimport {unstyled} from '../../../../output.js'\nimport {getLastFrameAfterUnmount} from '../../../../testing/ui.js'\nimport {AbortController, AbortSignal} from '../../../../public/node/abort.js'\nimport React from 'react'\nimport {describe, expect, test} from 'vitest'\nimport {render} from 'ink-testing-library'\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 }\n // When\n\n const renderInstance = render(\n <ConcurrentOutput processes={[backendProcess, frontendProcess]} abortController={new AbortController()} />,\n )\n\n // wait for all output to be rendered\n await frontendPromise\n\n // Then\n expect(unstyled(getLastFrameAfterUnmount(renderInstance)!).replace(/\\d/g, '0')).toMatchInlineSnapshot(`\n \"0000-00-00 00:00:00 | backend | first backend message\n 0000-00-00 00:00:00 | backend | second backend message\n 0000-00-00 00:00:00 | backend | third backend message\n 0000-00-00 00:00:00 | frontend | first frontend message\n 0000-00-00 00:00:00 | frontend | second frontend message\n 0000-00-00 00:00:00 | frontend | third frontend message\n \"\n `)\n })\n})\n"]}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { FatalError } from './FatalError.js';
|
|
2
|
-
import { renderString } from '../../ui.js';
|
|
3
2
|
import { unstyled } from '../../../../output.js';
|
|
4
3
|
import { Abort, Bug, ExternalError } from '../../../../error.js';
|
|
5
4
|
import { describe, expect, test } from 'vitest';
|
|
6
5
|
import React from 'react';
|
|
6
|
+
import { render } from 'ink-testing-library';
|
|
7
7
|
describe('FatalError', async () => {
|
|
8
8
|
test('renders correctly with a just a message and tryMessage', async () => {
|
|
9
9
|
const error = new Abort('test', 'try this');
|
|
10
|
-
const {
|
|
11
|
-
expect(unstyled(
|
|
10
|
+
const { lastFrame } = render(React.createElement(FatalError, { error: error }));
|
|
11
|
+
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
12
12
|
"
|
|
13
13
|
╭─ error ──────────────────────────────────────────────────────────────────────╮
|
|
14
14
|
│ │
|
|
@@ -29,8 +29,8 @@ describe('FatalError', async () => {
|
|
|
29
29
|
at Module.load (internal/modules/cjs/loader.js:985:32)
|
|
30
30
|
at Function.Module._load (internal/modules/cjs/loader.js:878:14)
|
|
31
31
|
`;
|
|
32
|
-
const {
|
|
33
|
-
expect(unstyled(
|
|
32
|
+
const { lastFrame } = render(React.createElement(FatalError, { error: error }));
|
|
33
|
+
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
34
34
|
"
|
|
35
35
|
╭─ error ──────────────────────────────────────────────────────────────────────╮
|
|
36
36
|
│ │
|
|
@@ -76,8 +76,8 @@ describe('FatalError', async () => {
|
|
|
76
76
|
},
|
|
77
77
|
],
|
|
78
78
|
];
|
|
79
|
-
const {
|
|
80
|
-
expect(unstyled(
|
|
79
|
+
const { lastFrame } = render(React.createElement(FatalError, { error: error }));
|
|
80
|
+
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
81
81
|
"
|
|
82
82
|
╭─ error ──────────────────────────────────────────────────────────────────────╮
|
|
83
83
|
│ │
|
|
@@ -102,8 +102,8 @@ describe('FatalError', async () => {
|
|
|
102
102
|
});
|
|
103
103
|
test('renders correctly an external error', async () => {
|
|
104
104
|
const error = new ExternalError('Unexpected error', 'yarn', ['install']);
|
|
105
|
-
const {
|
|
106
|
-
expect(unstyled(
|
|
105
|
+
const { lastFrame } = render(React.createElement(FatalError, { error: error }));
|
|
106
|
+
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
107
107
|
"
|
|
108
108
|
── external error ──────────────────────────────────────────────────────────────
|
|
109
109
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FatalError.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/FatalError.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"FatalError.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/FatalError.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAA;AAC9C,OAAO,EAAC,KAAK,EAAE,GAAG,EAAE,aAAa,EAAC,MAAM,sBAAsB,CAAA;AAC9D,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAA;AAE1C,QAAQ,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE;IAChC,IAAI,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;QAC3C,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,UAAU,IAAC,KAAK,EAAE,KAAK,GAAI,CAAC,CAAA;QAExD,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;KAUpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,kBAAkB,CAAC,CAAA;QACzC,KAAK,CAAC,KAAK,GAAG;;;;;;KAMb,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,UAAU,IAAC,KAAK,EAAE,KAAK,GAAI,CAAC,CAAA;QAExD,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;;;;;KAcpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,kBAAkB,CAAC,CAAA;QACzC,KAAK,CAAC,KAAK,GAAG;;;;;;KAMb,CAAA;QAED,KAAK,CAAC,SAAS,GAAG;YAChB;gBACE,UAAU;gBACV;oBACE,IAAI,EAAE;wBACJ,KAAK,EAAE,yCAAyC;wBAChD,GAAG,EAAE,qCAAqC;qBAC3C;iBACF;gBACD;oBACE,IAAI,EAAE,GAAG;iBACV;aACF;YACD,gEAAgE;YAChE;gBACE,gFAAgF;gBAChF;oBACE,OAAO,EAAE,SAAS;iBACnB;aACF;SACF,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,UAAU,IAAC,KAAK,EAAE,KAAK,GAAI,CAAC,CAAA;QAExD,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;;;;;;;;;;;;KAqBpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,KAAK,GAAG,IAAI,aAAa,CAAC,kBAAkB,EAAE,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC,CAAA;QAExE,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,UAAU,IAAC,KAAK,EAAE,KAAK,GAAI,CAAC,CAAA;QAExD,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;KAUpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {FatalError} from './FatalError.js'\nimport {unstyled} from '../../../../output.js'\nimport {Abort, Bug, ExternalError} from '../../../../error.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\nimport {render} from 'ink-testing-library'\n\ndescribe('FatalError', async () => {\n test('renders correctly with a just a message and tryMessage', async () => {\n const error = new Abort('test', 'try this')\n const {lastFrame} = render(<FatalError error={error} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"\n ╭─ error ──────────────────────────────────────────────────────────────────────╮\n │ │\n │ test │\n │ │\n │ try this │\n │ │\n ╰──────────────────────────────────────────────────────────────────────────────╯\n \"\n `)\n })\n\n test('renders correctly with a message and a stack', async () => {\n const error = new Bug('Unexpected error')\n error.stack = `\n Error: Unexpected error\n at Module._compile (internal/modules/cjs/loader.js:1137:30)\n at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)\n at Module.load (internal/modules/cjs/loader.js:985:32)\n at Function.Module._load (internal/modules/cjs/loader.js:878:14)\n `\n\n const {lastFrame} = render(<FatalError error={error} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"\n ╭─ error ──────────────────────────────────────────────────────────────────────╮\n │ │\n │ Unexpected error │\n │ │\n │ To investigate the issue, examine this stack trace: │\n │ at _compile (internal/modules/cjs/loader.js:1137) │\n │ at js (internal/modules/cjs/loader.js:1157) │\n │ at load (internal/modules/cjs/loader.js:985) │\n │ at _load (internal/modules/cjs/loader.js:878) │\n │ │\n ╰──────────────────────────────────────────────────────────────────────────────╯\n \"\n `)\n })\n\n test('renders correctly with a message, a stack, and next steps', async () => {\n const error = new Bug('Unexpected error')\n error.stack = `\n Error: Unexpected error\n at Module._compile (internal/modules/cjs/loader.js:1137:30)\n at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)\n at Module.load (internal/modules/cjs/loader.js:985:32)\n at Function.Module._load (internal/modules/cjs/loader.js:878:14)\n `\n\n error.nextSteps = [\n [\n 'Have you',\n {\n link: {\n label: 'created a Shopify Partners organization',\n url: 'https://partners.shopify.com/signup',\n },\n },\n {\n char: '?',\n },\n ],\n 'Have you confirmed your accounts from the emails you received?',\n [\n 'Need to connect to a different App or organization? Run the command again with',\n {\n command: '--reset',\n },\n ],\n ]\n\n const {lastFrame} = render(<FatalError error={error} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"\n ╭─ error ──────────────────────────────────────────────────────────────────────╮\n │ │\n │ Unexpected error │\n │ │\n │ Next steps │\n │ • Have you created a Shopify Partners organization ( │\n │ https://partners.shopify.com/signup )? │\n │ • Have you confirmed your accounts from the emails you received? │\n │ • Need to connect to a different App or organization? Run the command │\n │ again with \\`--reset\\` │\n │ │\n │ To investigate the issue, examine this stack trace: │\n │ at _compile (internal/modules/cjs/loader.js:1137) │\n │ at js (internal/modules/cjs/loader.js:1157) │\n │ at load (internal/modules/cjs/loader.js:985) │\n │ at _load (internal/modules/cjs/loader.js:878) │\n │ │\n ╰──────────────────────────────────────────────────────────────────────────────╯\n \"\n `)\n })\n\n test('renders correctly an external error', async () => {\n const error = new ExternalError('Unexpected error', 'yarn', ['install'])\n\n const {lastFrame} = render(<FatalError error={error} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"\n ── external error ──────────────────────────────────────────────────────────────\n\n Error coming from \\`yarn install\\`\n\n Unexpected error\n\n ────────────────────────────────────────────────────────────────────────────────\n \"\n `)\n })\n})\n"]}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { FilePath } from './FilePath.js';
|
|
2
|
-
import { renderString } from '../../ui.js';
|
|
3
2
|
import { describe, expect, test } from 'vitest';
|
|
4
3
|
import React from 'react';
|
|
4
|
+
import { render } from 'ink-testing-library';
|
|
5
5
|
describe('FilePath', async () => {
|
|
6
6
|
test('renders correctly', async () => {
|
|
7
|
-
const {
|
|
8
|
-
expect(
|
|
7
|
+
const { lastFrame } = render(React.createElement(FilePath, { filePath: "src/this/is/a/test.js" }));
|
|
8
|
+
expect(lastFrame()).toMatchInlineSnapshot('"\\"src/this/is/a/test.js\\""');
|
|
9
9
|
});
|
|
10
10
|
});
|
|
11
11
|
//# sourceMappingURL=FilePath.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilePath.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/FilePath.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAA;AACtC,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"FilePath.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/FilePath.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAA;AACtC,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAA;AAE1C,QAAQ,CAAC,UAAU,EAAE,KAAK,IAAI,EAAE;IAC9B,IAAI,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,QAAQ,IAAC,QAAQ,EAAC,uBAAuB,GAAG,CAAC,CAAA;QAEzE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,qBAAqB,CAAC,+BAA+B,CAAC,CAAA;IAC5E,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {FilePath} from './FilePath.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\nimport {render} from 'ink-testing-library'\n\ndescribe('FilePath', async () => {\n test('renders correctly', async () => {\n const {lastFrame} = render(<FilePath filePath=\"src/this/is/a/test.js\" />)\n\n expect(lastFrame()).toMatchInlineSnapshot('\"\\\\\"src/this/is/a/test.js\\\\\"\"')\n })\n})\n"]}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { Link } from './Link.js';
|
|
2
|
-
import { renderString } from '../../ui.js';
|
|
3
2
|
import { describe, expect, test } from 'vitest';
|
|
4
3
|
import React from 'react';
|
|
4
|
+
import { render } from 'ink-testing-library';
|
|
5
5
|
describe('Link', async () => {
|
|
6
6
|
test("renders correctly with a fallback for terminals that don't support hyperlinks", async () => {
|
|
7
7
|
const link = {
|
|
8
8
|
url: 'https://example.com',
|
|
9
9
|
label: 'Example',
|
|
10
10
|
};
|
|
11
|
-
const {
|
|
12
|
-
expect(
|
|
11
|
+
const { lastFrame } = render(React.createElement(Link, { ...link }));
|
|
12
|
+
expect(lastFrame()).toMatchInlineSnapshot('"Example [2m( https://example.com )[22m"');
|
|
13
13
|
});
|
|
14
14
|
test("it doesn't render a fallback if only url is passed", async () => {
|
|
15
15
|
const link = {
|
|
16
16
|
url: 'https://example.com',
|
|
17
17
|
};
|
|
18
|
-
const {
|
|
19
|
-
expect(
|
|
18
|
+
const { lastFrame } = render(React.createElement(Link, { ...link }));
|
|
19
|
+
expect(lastFrame()).toMatchInlineSnapshot('"https://example.com"');
|
|
20
20
|
});
|
|
21
21
|
});
|
|
22
22
|
//# sourceMappingURL=Link.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Link.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Link.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"Link.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Link.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAA;AAE1C,QAAQ,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;IAC1B,IAAI,CAAC,+EAA+E,EAAE,KAAK,IAAI,EAAE;QAC/F,MAAM,IAAI,GAAG;YACX,GAAG,EAAE,qBAAqB;YAC1B,KAAK,EAAE,SAAS;SACjB,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,IAAI,OAAK,IAAI,GAAI,CAAC,CAAA;QAE9C,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,qBAAqB,CAAC,4CAA4C,CAAC,CAAA;IACzF,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,IAAI,GAAG;YACX,GAAG,EAAE,qBAAqB;SAC3B,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,IAAI,OAAK,IAAI,GAAI,CAAC,CAAA;QAE9C,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,qBAAqB,CAAC,uBAAuB,CAAC,CAAA;IACpE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {Link} from './Link.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\nimport {render} from 'ink-testing-library'\n\ndescribe('Link', async () => {\n test(\"renders correctly with a fallback for terminals that don't support hyperlinks\", async () => {\n const link = {\n url: 'https://example.com',\n label: 'Example',\n }\n\n const {lastFrame} = render(<Link {...link} />)\n\n expect(lastFrame()).toMatchInlineSnapshot('\"Example \u001b[2m( https://example.com )\u001b[22m\"')\n })\n\n test(\"it doesn't render a fallback if only url is passed\", async () => {\n const link = {\n url: 'https://example.com',\n }\n\n const {lastFrame} = render(<Link {...link} />)\n\n expect(lastFrame()).toMatchInlineSnapshot('\"https://example.com\"')\n })\n})\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { List } from './List.js';
|
|
2
|
-
import { renderString } from '../../ui.js';
|
|
3
2
|
import { unstyled } from '../../../../output.js';
|
|
4
3
|
import { describe, expect, test } from 'vitest';
|
|
5
4
|
import React from 'react';
|
|
5
|
+
import { render } from 'ink-testing-library';
|
|
6
6
|
describe('List', async () => {
|
|
7
7
|
test('renders unordered items', async () => {
|
|
8
8
|
const options = {
|
|
@@ -10,8 +10,8 @@ describe('List', async () => {
|
|
|
10
10
|
items: ['Item 1', 'Item 2', 'Item 3'],
|
|
11
11
|
ordered: false,
|
|
12
12
|
};
|
|
13
|
-
const {
|
|
14
|
-
expect(unstyled(
|
|
13
|
+
const { lastFrame } = render(React.createElement(List, { ...options }));
|
|
14
|
+
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
15
15
|
"List title
|
|
16
16
|
• Item 1
|
|
17
17
|
• Item 2
|
|
@@ -23,8 +23,8 @@ describe('List', async () => {
|
|
|
23
23
|
items: ['Item 1', 'Item 2', 'Item 3'],
|
|
24
24
|
ordered: true,
|
|
25
25
|
};
|
|
26
|
-
const {
|
|
27
|
-
expect(unstyled(
|
|
26
|
+
const { lastFrame } = render(React.createElement(List, { ...options }));
|
|
27
|
+
expect(unstyled(lastFrame())).toMatchInlineSnapshot(`
|
|
28
28
|
" 1. Item 1
|
|
29
29
|
2. Item 2
|
|
30
30
|
3. Item 3"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"List.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/List.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"List.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/List.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,QAAQ,EAAC,MAAM,uBAAuB,CAAA;AAC9C,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAC,MAAM,EAAC,MAAM,qBAAqB,CAAA;AAE1C,QAAQ,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;IAC1B,IAAI,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,OAAO,GAAG;YACd,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;YACrC,OAAO,EAAE,KAAK;SACf,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,IAAI,OAAK,OAAO,GAAI,CAAC,CAAA;QAEjD,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;KAKpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;QACvC,MAAM,OAAO,GAAG;YACd,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;YACrC,OAAO,EAAE,IAAI;SACd,CAAA;QAED,MAAM,EAAC,SAAS,EAAC,GAAG,MAAM,CAAC,oBAAC,IAAI,OAAK,OAAO,GAAI,CAAC,CAAA;QAEjD,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;KAIpD,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {List} from './List.js'\nimport {unstyled} from '../../../../output.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\nimport {render} from 'ink-testing-library'\n\ndescribe('List', async () => {\n test('renders unordered items', async () => {\n const options = {\n title: 'List title',\n items: ['Item 1', 'Item 2', 'Item 3'],\n ordered: false,\n }\n\n const {lastFrame} = render(<List {...options} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"List title\n • Item 1\n • Item 2\n • Item 3\"\n `)\n })\n\n test('renders ordered items', async () => {\n const options = {\n items: ['Item 1', 'Item 2', 'Item 3'],\n ordered: true,\n }\n\n const {lastFrame} = render(<List {...options} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \" 1. Item 1\n 2. Item 2\n 3. Item 3\"\n `)\n })\n})\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
export interface Props<T> {
|
|
3
3
|
items: Item<T>[];
|
|
4
|
-
|
|
4
|
+
onChange: (item: Item<T>) => void;
|
|
5
5
|
}
|
|
6
6
|
export interface Item<T> {
|
|
7
7
|
label: string;
|
|
@@ -9,4 +9,4 @@ export interface Item<T> {
|
|
|
9
9
|
key?: string;
|
|
10
10
|
group?: string;
|
|
11
11
|
}
|
|
12
|
-
export default function SelectInput<T>({ items,
|
|
12
|
+
export default function SelectInput<T>({ items, onChange }: React.PropsWithChildren<Props<T>>): JSX.Element | null;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { isTruthy } from '../../../../environment/utilities.js';
|
|
2
1
|
import { isEqual } from '../../../../public/common/lang.js';
|
|
3
2
|
import { groupBy } from '../../../../public/common/collection.js';
|
|
4
3
|
import { mapValues } from '../../../../public/common/object.js';
|
|
5
4
|
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
6
|
-
import { Box,
|
|
5
|
+
import { Box, useInput, Text } from 'ink';
|
|
7
6
|
function groupItems(items) {
|
|
8
7
|
let index = 0;
|
|
9
8
|
return mapValues(groupBy(items, 'group'), (groupItems) => groupItems.map((groupItem) => {
|
|
@@ -12,53 +11,46 @@ function groupItems(items) {
|
|
|
12
11
|
return item;
|
|
13
12
|
}));
|
|
14
13
|
}
|
|
15
|
-
export default function SelectInput({ items,
|
|
14
|
+
export default function SelectInput({ items, onChange }) {
|
|
16
15
|
const [inputStack, setInputStack] = useState(null);
|
|
17
16
|
const [inputTimeout, setInputTimeout] = useState(null);
|
|
18
17
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
19
18
|
const keys = useRef(new Set(items.map((item) => item.key)));
|
|
20
|
-
const { exit: unmountInk } = useApp();
|
|
21
19
|
const groupedItems = groupItems(items);
|
|
20
|
+
const groupedItemsValues = Object.values(groupedItems).flat();
|
|
22
21
|
const groupTitles = Object.keys(groupedItems);
|
|
23
22
|
const previousItems = useRef(items);
|
|
23
|
+
const changeSelection = useCallback((index) => {
|
|
24
|
+
const groupedItem = groupedItemsValues.find((item) => item.index === index);
|
|
25
|
+
setSelectedIndex(index);
|
|
26
|
+
onChange(items.find((item) => item.value === groupedItem.value));
|
|
27
|
+
}, [items]);
|
|
24
28
|
// reset index when items change
|
|
25
29
|
useEffect(() => {
|
|
26
30
|
if (!isEqual(previousItems.current.map((item) => item.value), items.map((item) => item.value))) {
|
|
27
|
-
|
|
31
|
+
changeSelection(0);
|
|
28
32
|
}
|
|
29
33
|
previousItems.current = items;
|
|
30
34
|
}, [items]);
|
|
31
35
|
const handleInput = useCallback((input, key) => {
|
|
32
|
-
if (input === 'c' && key.ctrl) {
|
|
33
|
-
// Exceptions being throw in these hooks aren't being caught by our errorHandler.
|
|
34
|
-
// See also how we handle exceptions in CouncurrentOutput for reference.
|
|
35
|
-
process.exit(1);
|
|
36
|
-
}
|
|
37
36
|
const parsedInput = parseInt(input, 10);
|
|
38
37
|
if (parsedInput !== 0 && parsedInput <= items.length + 1) {
|
|
39
|
-
|
|
38
|
+
changeSelection(parsedInput - 1);
|
|
40
39
|
}
|
|
41
40
|
else if (keys.current.has(input)) {
|
|
42
|
-
const
|
|
43
|
-
if (
|
|
44
|
-
|
|
41
|
+
const groupedItem = groupedItemsValues.find((item) => item.key === input);
|
|
42
|
+
if (groupedItem !== undefined) {
|
|
43
|
+
changeSelection(groupedItem.index);
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
46
|
if (key.upArrow) {
|
|
48
47
|
const lastIndex = items.length - 1;
|
|
49
|
-
|
|
48
|
+
changeSelection(selectedIndex === 0 ? lastIndex : selectedIndex - 1);
|
|
50
49
|
}
|
|
51
50
|
else if (key.downArrow) {
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
else if (key.return) {
|
|
55
|
-
onSelect(items[selectedIndex].value);
|
|
56
|
-
// This is a workaround needed because Ink behaves differently in CI when
|
|
57
|
-
// unmounting. See https://github.com/vadimdemedes/ink/pull/266
|
|
58
|
-
if (!isTruthy(process.env.CI))
|
|
59
|
-
unmountInk();
|
|
51
|
+
changeSelection(selectedIndex === items.length - 1 ? 0 : selectedIndex + 1);
|
|
60
52
|
}
|
|
61
|
-
}, [selectedIndex, items
|
|
53
|
+
}, [selectedIndex, items]);
|
|
62
54
|
useInput((input, key) => {
|
|
63
55
|
if (input.length > 0 && Object.values(key).every((value) => value === false)) {
|
|
64
56
|
const newInputStack = inputStack === null ? input : inputStack + input;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectInput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SelectInput.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,
|
|
1
|
+
{"version":3,"file":"SelectInput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/SelectInput.tsx"],"names":[],"mappings":"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","sourcesContent":["import {isEqual} from '../../../../public/common/lang.js'\nimport {groupBy} from '../../../../public/common/collection.js'\nimport {mapValues} from '../../../../public/common/object.js'\nimport React, {useState, useEffect, useRef, useCallback} from 'react'\nimport {Box, Key, useInput, Text} from 'ink'\n\nexport interface Props<T> {\n items: Item<T>[]\n onChange: (item: Item<T>) => void\n}\n\nexport interface Item<T> {\n label: string\n value: T\n key?: string\n group?: string\n}\n\nfunction groupItems<T>(items: Item<T>[]) {\n let index = 0\n\n return mapValues(groupBy(items, 'group'), (groupItems) =>\n groupItems.map((groupItem) => {\n const item = {...groupItem, key: groupItem.key ?? (index + 1).toString(), index}\n index += 1\n return item\n }),\n )\n}\n\nexport default function SelectInput<T>({items, onChange}: React.PropsWithChildren<Props<T>>): JSX.Element | null {\n const [inputStack, setInputStack] = useState<string | null>(null)\n const [inputTimeout, setInputTimeout] = useState<NodeJS.Timeout | null>(null)\n const [selectedIndex, setSelectedIndex] = useState(0)\n const keys = useRef(new Set(items.map((item) => item.key)))\n const groupedItems = groupItems(items)\n const groupedItemsValues = Object.values(groupedItems).flat()\n const groupTitles = Object.keys(groupedItems)\n const previousItems = useRef<Item<T>[]>(items)\n\n const changeSelection = useCallback(\n (index: number) => {\n const groupedItem = groupedItemsValues.find((item) => item.index === index)!\n setSelectedIndex(index)\n onChange(items.find((item) => item.value === groupedItem.value)!)\n },\n [items],\n )\n\n // reset index when items change\n useEffect(() => {\n if (\n !isEqual(\n previousItems.current.map((item) => item.value),\n items.map((item) => item.value),\n )\n ) {\n changeSelection(0)\n }\n\n previousItems.current = items\n }, [items])\n\n const handleInput = useCallback(\n (input: string, key: Key) => {\n const parsedInput = parseInt(input, 10)\n\n if (parsedInput !== 0 && parsedInput <= items.length + 1) {\n changeSelection(parsedInput - 1)\n } else if (keys.current.has(input)) {\n const groupedItem = groupedItemsValues.find((item) => item.key === input)\n if (groupedItem !== undefined) {\n changeSelection(groupedItem.index)\n }\n }\n\n if (key.upArrow) {\n const lastIndex = items.length - 1\n\n changeSelection(selectedIndex === 0 ? lastIndex : selectedIndex - 1)\n } else if (key.downArrow) {\n changeSelection(selectedIndex === items.length - 1 ? 0 : selectedIndex + 1)\n }\n },\n [selectedIndex, items],\n )\n\n useInput((input, key) => {\n if (input.length > 0 && Object.values(key).every((value) => value === false)) {\n const newInputStack = inputStack === null ? input : inputStack + input\n\n setInputStack(newInputStack)\n\n if (inputTimeout !== null) {\n clearTimeout(inputTimeout)\n }\n\n setInputTimeout(\n setTimeout(() => {\n handleInput(newInputStack, key)\n setInputStack(null)\n setInputTimeout(null)\n }, 300),\n )\n } else {\n handleInput(input, key)\n }\n })\n\n return (\n <Box flexDirection=\"column\">\n {groupTitles.map((title) => {\n const hasTitle = title !== 'undefined'\n\n return (\n <Box key={title} flexDirection=\"column\" marginTop={hasTitle ? 1 : 0}>\n {hasTitle && (\n <Box marginLeft={3}>\n <Text bold>{title}</Text>\n </Box>\n )}\n {groupedItems[title]!.map((item) => {\n const isSelected = item.index === selectedIndex\n\n return (\n <Box key={item.key}>\n <Box marginRight={2}>{isSelected ? <Text color=\"cyan\">{`>`}</Text> : <Text> </Text>}</Box>\n\n <Text color={isSelected ? 'cyan' : undefined}>{`(${item.key}) ${item.label}`}</Text>\n </Box>\n )\n })}\n </Box>\n )\n })}\n\n <Box marginTop={1} marginLeft={3}>\n <Text dimColor>navigate with arrows, enter to select</Text>\n </Box>\n </Box>\n )\n}\n"]}
|