@shopify/cli-kit 3.24.1 → 3.25.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.
Files changed (77) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/api/graphql/functions/app_function_set.d.ts +1 -0
  3. package/dist/api/graphql/functions/app_function_set.js +2 -0
  4. package/dist/api/graphql/functions/app_function_set.js.map +1 -1
  5. package/dist/index.d.ts +0 -1
  6. package/dist/index.js +0 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/plugins.d.ts +1 -1
  9. package/dist/plugins.js +1 -1
  10. package/dist/plugins.js.map +1 -1
  11. package/dist/private/node/ui/components/Alert.d.ts +1 -1
  12. package/dist/private/node/ui/components/Alert.js +2 -2
  13. package/dist/private/node/ui/components/Alert.js.map +1 -1
  14. package/dist/private/node/ui/components/Alert.test.d.ts +1 -0
  15. package/dist/private/node/ui/components/Alert.test.js +95 -0
  16. package/dist/private/node/ui/components/Alert.test.js.map +1 -0
  17. package/dist/private/node/ui/components/Banner.js +8 -9
  18. package/dist/private/node/ui/components/Banner.js.map +1 -1
  19. package/dist/private/node/ui/components/Banner.test.d.ts +1 -0
  20. package/dist/private/node/ui/components/Banner.test.js +52 -0
  21. package/dist/private/node/ui/components/Banner.test.js.map +1 -0
  22. package/dist/private/node/ui/components/Command.test.d.ts +1 -0
  23. package/dist/private/node/ui/components/Command.test.js +11 -0
  24. package/dist/private/node/ui/components/Command.test.js.map +1 -0
  25. package/dist/private/node/ui/components/ConcurrentOutput.js +0 -1
  26. package/dist/private/node/ui/components/ConcurrentOutput.js.map +1 -1
  27. package/dist/private/node/ui/components/FatalError.js +1 -1
  28. package/dist/private/node/ui/components/FatalError.js.map +1 -1
  29. package/dist/private/node/ui/components/FatalError.test.d.ts +1 -0
  30. package/dist/private/node/ui/components/FatalError.test.js +119 -0
  31. package/dist/private/node/ui/components/FatalError.test.js.map +1 -0
  32. package/dist/private/node/ui/components/FilePath.d.ts +9 -0
  33. package/dist/private/node/ui/components/FilePath.js +13 -0
  34. package/dist/private/node/ui/components/FilePath.js.map +1 -0
  35. package/dist/private/node/ui/components/FilePath.test.d.ts +1 -0
  36. package/dist/private/node/ui/components/FilePath.test.js +11 -0
  37. package/dist/private/node/ui/components/FilePath.test.js.map +1 -0
  38. package/dist/private/node/ui/components/Link.js +6 -5
  39. package/dist/private/node/ui/components/Link.js.map +1 -1
  40. package/dist/private/node/ui/components/Link.test.d.ts +1 -0
  41. package/dist/private/node/ui/components/Link.test.js +22 -0
  42. package/dist/private/node/ui/components/Link.test.js.map +1 -0
  43. package/dist/private/node/ui/components/List.d.ts +1 -1
  44. package/dist/private/node/ui/components/List.js +2 -2
  45. package/dist/private/node/ui/components/List.js.map +1 -1
  46. package/dist/private/node/ui/components/List.test.d.ts +1 -0
  47. package/dist/private/node/ui/components/List.test.js +34 -0
  48. package/dist/private/node/ui/components/List.test.js.map +1 -0
  49. package/dist/private/node/ui/components/TokenizedText.d.ts +13 -1
  50. package/dist/private/node/ui/components/TokenizedText.js +47 -6
  51. package/dist/private/node/ui/components/TokenizedText.js.map +1 -1
  52. package/dist/private/node/ui/components/TokenizedText.test.d.ts +1 -0
  53. package/dist/private/node/ui/components/TokenizedText.test.js +44 -0
  54. package/dist/private/node/ui/components/TokenizedText.test.js.map +1 -0
  55. package/dist/private/node/ui/components/UserInput.d.ts +10 -0
  56. package/dist/private/node/ui/components/UserInput.js +11 -0
  57. package/dist/private/node/ui/components/UserInput.js.map +1 -0
  58. package/dist/private/node/ui/components/UserInput.test.d.ts +1 -0
  59. package/dist/private/node/ui/components/UserInput.test.js +11 -0
  60. package/dist/private/node/ui/components/UserInput.test.js.map +1 -0
  61. package/dist/public/node/github.d.ts +50 -0
  62. package/dist/{github.js → public/node/github.js} +29 -14
  63. package/dist/public/node/github.js.map +1 -0
  64. package/dist/public/node/plugins/tunnel.d.ts +1 -1
  65. package/dist/public/node/plugins/tunnel.js +1 -1
  66. package/dist/public/node/plugins/tunnel.js.map +1 -1
  67. package/dist/public/{common → node}/result.d.ts +12 -6
  68. package/dist/public/{common → node}/result.js +28 -5
  69. package/dist/public/node/result.js.map +1 -0
  70. package/dist/session/exchange.d.ts +1 -1
  71. package/dist/session/exchange.js +4 -4
  72. package/dist/session/exchange.js.map +1 -1
  73. package/dist/tsconfig.tsbuildinfo +1 -1
  74. package/package.json +1 -1
  75. package/dist/github.d.ts +0 -33
  76. package/dist/github.js.map +0 -1
  77. package/dist/public/common/result.js.map +0 -1
@@ -0,0 +1,119 @@
1
+ import { FatalError } from './FatalError.js';
2
+ import { renderString } from '../../ui.js';
3
+ import { unstyled } from '../../../../output.js';
4
+ import { Abort, Bug, ExternalError } from '../../../../error.js';
5
+ import { describe, expect, test } from 'vitest';
6
+ import React from 'react';
7
+ describe('FatalError', async () => {
8
+ test('renders correctly with a just a message and tryMessage', async () => {
9
+ const error = new Abort('test', 'try this');
10
+ const { output } = renderString(React.createElement(FatalError, { error: error }));
11
+ expect(unstyled(output)).toMatchInlineSnapshot(`
12
+ "
13
+ ╭─ error ──────────────────────────────────────────────────────────────────────╮
14
+ │ │
15
+ │ test │
16
+ │ │
17
+ │ try this │
18
+ │ │
19
+ ╰──────────────────────────────────────────────────────────────────────────────╯
20
+ "
21
+ `);
22
+ });
23
+ test('renders correctly with a message and a stack', async () => {
24
+ const error = new Bug('Unexpected error');
25
+ error.stack = `
26
+ Error: Unexpected error
27
+ at Module._compile (internal/modules/cjs/loader.js:1137:30)
28
+ at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
29
+ at Module.load (internal/modules/cjs/loader.js:985:32)
30
+ at Function.Module._load (internal/modules/cjs/loader.js:878:14)
31
+ `;
32
+ const { output } = renderString(React.createElement(FatalError, { error: error }));
33
+ expect(unstyled(output)).toMatchInlineSnapshot(`
34
+ "
35
+ ╭─ error ──────────────────────────────────────────────────────────────────────╮
36
+ │ │
37
+ │ Unexpected error │
38
+ │ │
39
+ │ To investigate the issue, examine this stack trace: │
40
+ │ at _compile (internal/modules/cjs/loader.js:1137) │
41
+ │ at js (internal/modules/cjs/loader.js:1157) │
42
+ │ at load (internal/modules/cjs/loader.js:985) │
43
+ │ at _load (internal/modules/cjs/loader.js:878) │
44
+ │ │
45
+ ╰──────────────────────────────────────────────────────────────────────────────╯
46
+ "
47
+ `);
48
+ });
49
+ test('renders correctly with a message, a stack, and next steps', async () => {
50
+ const error = new Bug('Unexpected error');
51
+ error.stack = `
52
+ Error: Unexpected error
53
+ at Module._compile (internal/modules/cjs/loader.js:1137:30)
54
+ at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
55
+ at Module.load (internal/modules/cjs/loader.js:985:32)
56
+ at Function.Module._load (internal/modules/cjs/loader.js:878:14)
57
+ `;
58
+ error.nextSteps = [
59
+ [
60
+ 'Have you',
61
+ {
62
+ link: {
63
+ label: 'created a Shopify Partners organization',
64
+ url: 'https://partners.shopify.com/signup',
65
+ },
66
+ },
67
+ {
68
+ char: '?',
69
+ },
70
+ ],
71
+ 'Have you confirmed your accounts from the emails you received?',
72
+ [
73
+ 'Need to connect to a different App or organization? Run the command again with',
74
+ {
75
+ command: '--reset',
76
+ },
77
+ ],
78
+ ];
79
+ const { output } = renderString(React.createElement(FatalError, { error: error }));
80
+ expect(unstyled(output)).toMatchInlineSnapshot(`
81
+ "
82
+ ╭─ error ──────────────────────────────────────────────────────────────────────╮
83
+ │ │
84
+ │ Unexpected error │
85
+ │ │
86
+ │ Next steps │
87
+ │ • Have you created a Shopify Partners organization │
88
+ │ (https://partners.shopify.com/signup)? │
89
+ │ • Have you confirmed your accounts from the emails you received? │
90
+ │ • Need to connect to a different App or organization? Run the command │
91
+ │ again with \`--reset\` │
92
+ │ │
93
+ │ To investigate the issue, examine this stack trace: │
94
+ │ at _compile (internal/modules/cjs/loader.js:1137) │
95
+ │ at js (internal/modules/cjs/loader.js:1157) │
96
+ │ at load (internal/modules/cjs/loader.js:985) │
97
+ │ at _load (internal/modules/cjs/loader.js:878) │
98
+ │ │
99
+ ╰──────────────────────────────────────────────────────────────────────────────╯
100
+ "
101
+ `);
102
+ });
103
+ test('renders correctly an external error', async () => {
104
+ const error = new ExternalError('Unexpected error', 'yarn', ['install']);
105
+ const { output } = renderString(React.createElement(FatalError, { error: error }));
106
+ expect(unstyled(output)).toMatchInlineSnapshot(`
107
+ "
108
+ ── external error ──────────────────────────────────────────────────────────────
109
+
110
+ Error coming from \`yarn install\`
111
+
112
+ Unexpected error
113
+
114
+ ────────────────────────────────────────────────────────────────────────────────
115
+ "
116
+ `);
117
+ });
118
+ });
119
+ //# sourceMappingURL=FatalError.test.js.map
@@ -0,0 +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,YAAY,EAAC,MAAM,aAAa,CAAA;AACxC,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;AAEzB,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,MAAM,EAAC,GAAG,YAAY,CAAC,oBAAC,UAAU,IAAC,KAAK,EAAE,KAAK,GAAI,CAAC,CAAA;QAE3D,MAAM,CAAC,QAAQ,CAAC,MAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;KAU/C,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,MAAM,EAAC,GAAG,YAAY,CAAC,oBAAC,UAAU,IAAC,KAAK,EAAE,KAAK,GAAI,CAAC,CAAA;QAE3D,MAAM,CAAC,QAAQ,CAAC,MAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;;;;;KAc/C,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,MAAM,EAAC,GAAG,YAAY,CAAC,oBAAC,UAAU,IAAC,KAAK,EAAE,KAAK,GAAI,CAAC,CAAA;QAE3D,MAAM,CAAC,QAAQ,CAAC,MAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;;;;;;;;;;;;KAqB/C,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,MAAM,EAAC,GAAG,YAAY,CAAC,oBAAC,UAAU,IAAC,KAAK,EAAE,KAAK,GAAI,CAAC,CAAA;QAE3D,MAAM,CAAC,QAAQ,CAAC,MAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;;KAU/C,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {FatalError} from './FatalError.js'\nimport {renderString} from '../../ui.js'\nimport {unstyled} from '../../../../output.js'\nimport {Abort, Bug, ExternalError} from '../../../../error.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\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 {output} = renderString(<FatalError error={error} />)\n\n expect(unstyled(output!)).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 {output} = renderString(<FatalError error={error} />)\n\n expect(unstyled(output!)).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 {output} = renderString(<FatalError error={error} />)\n\n expect(unstyled(output!)).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 {output} = renderString(<FatalError error={error} />)\n\n expect(unstyled(output!)).toMatchInlineSnapshot(`\n \"\n ── external error ──────────────────────────────────────────────────────────────\n\n Error coming from \\`yarn install\\`\n\n Unexpected error\n\n ────────────────────────────────────────────────────────────────────────────────\n \"\n `)\n })\n})\n"]}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ interface Props {
3
+ filePath: string;
4
+ }
5
+ /**
6
+ * `FilePath` displays a path to a file.
7
+ */
8
+ declare const FilePath: React.FC<Props>;
9
+ export { FilePath };
@@ -0,0 +1,13 @@
1
+ import { Text } from 'ink';
2
+ import React from 'react';
3
+ /**
4
+ * `FilePath` displays a path to a file.
5
+ */
6
+ const FilePath = ({ filePath }) => {
7
+ return React.createElement(Text, null,
8
+ "\"",
9
+ filePath,
10
+ "\"");
11
+ };
12
+ export { FilePath };
13
+ //# sourceMappingURL=FilePath.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FilePath.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/FilePath.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,KAAK,CAAA;AACxB,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB;;GAEG;AACH,MAAM,QAAQ,GAAoB,CAAC,EAAC,QAAQ,EAAiC,EAAe,EAAE;IAC5F,OAAO,oBAAC,IAAI;;QAAG,QAAQ;aAAS,CAAA;AAClC,CAAC,CAAA;AAED,OAAO,EAAC,QAAQ,EAAC,CAAA","sourcesContent":["import {Text} from 'ink'\nimport React from 'react'\n\ninterface Props {\n filePath: string\n}\n\n/**\n * `FilePath` displays a path to a file.\n */\nconst FilePath: React.FC<Props> = ({filePath}: React.PropsWithChildren<Props>): JSX.Element => {\n return <Text>\"{filePath}\"</Text>\n}\n\nexport {FilePath}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import { FilePath } from './FilePath.js';
2
+ import { renderString } from '../../ui.js';
3
+ import { describe, expect, test } from 'vitest';
4
+ import React from 'react';
5
+ describe('FilePath', async () => {
6
+ test('renders correctly', async () => {
7
+ const { output } = renderString(React.createElement(FilePath, { filePath: "src/this/is/a/test.js" }));
8
+ expect(output).toMatchInlineSnapshot('"\\"src/this/is/a/test.js\\""');
9
+ });
10
+ });
11
+ //# sourceMappingURL=FilePath.test.js.map
@@ -0,0 +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,YAAY,EAAC,MAAM,aAAa,CAAA;AACxC,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,QAAQ,CAAC,UAAU,EAAE,KAAK,IAAI,EAAE;IAC9B,IAAI,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,EAAC,MAAM,EAAC,GAAG,YAAY,CAAC,oBAAC,QAAQ,IAAC,QAAQ,EAAC,uBAAuB,GAAG,CAAC,CAAA;QAE5E,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,+BAA+B,CAAC,CAAA;IACvE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {FilePath} from './FilePath.js'\nimport {renderString} from '../../ui.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\n\ndescribe('FilePath', async () => {\n test('renders correctly', async () => {\n const {output} = renderString(<FilePath filePath=\"src/this/is/a/test.js\" />)\n\n expect(output).toMatchInlineSnapshot('\"\\\\\"src/this/is/a/test.js\\\\\"\"')\n })\n})\n"]}
@@ -1,14 +1,15 @@
1
- import { Text, Transform } from 'ink';
1
+ import chalk from 'chalk';
2
+ import { Text } from 'ink';
2
3
  import React from 'react';
3
4
  import terminalLink from 'terminal-link';
5
+ function fallback(text, url) {
6
+ return `${text} ${chalk.dim(`(${url})`)}`;
7
+ }
4
8
  /**
5
9
  * `Link` displays a clickable link when supported by the terminal.
6
10
  */
7
11
  const Link = ({ url, label }) => {
8
- return (React.createElement(Text, null,
9
- label && React.createElement(Text, { dimColor: true }, `${label}: `),
10
- React.createElement(Transform, { transform: (children) => terminalLink(children, url, { fallback: false }) },
11
- React.createElement(Text, { underline: true }, url))));
12
+ return React.createElement(Text, null, terminalLink(label ?? url, url, { fallback: label ? fallback : false }));
12
13
  };
13
14
  export { Link };
14
15
  //# sourceMappingURL=Link.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Link.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Link.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAE,SAAS,EAAC,MAAM,KAAK,CAAA;AACnC,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,YAAY,MAAM,eAAe,CAAA;AAOxC;;GAEG;AACH,MAAM,IAAI,GAAoB,CAAC,EAAC,GAAG,EAAE,KAAK,EAAiC,EAAe,EAAE;IAC1F,OAAO,CACL,oBAAC,IAAI;QACF,KAAK,IAAI,oBAAC,IAAI,IAAC,QAAQ,UAAE,GAAG,KAAK,IAAI,CAAQ;QAC9C,oBAAC,SAAS,IAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAC,QAAQ,EAAE,KAAK,EAAC,CAAC;YAChF,oBAAC,IAAI,IAAC,SAAS,UAAE,GAAG,CAAQ,CAClB,CACP,CACR,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,IAAI,EAAC,CAAA","sourcesContent":["import {Text, Transform} from 'ink'\nimport React from 'react'\nimport terminalLink from 'terminal-link'\n\ninterface Props {\n url: string\n label?: string\n}\n\n/**\n * `Link` displays a clickable link when supported by the terminal.\n */\nconst Link: React.FC<Props> = ({url, label}: React.PropsWithChildren<Props>): JSX.Element => {\n return (\n <Text>\n {label && <Text dimColor>{`${label}: `}</Text>}\n <Transform transform={(children) => terminalLink(children, url, {fallback: false})}>\n <Text underline>{url}</Text>\n </Transform>\n </Text>\n )\n}\n\nexport {Link}\n"]}
1
+ {"version":3,"file":"Link.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/Link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAC,IAAI,EAAC,MAAM,KAAK,CAAA;AACxB,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,YAAY,MAAM,eAAe,CAAA;AAOxC,SAAS,QAAQ,CAAC,IAAY,EAAE,GAAW;IACzC,OAAO,GAAG,IAAI,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,EAAE,CAAA;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,IAAI,GAAoB,CAAC,EAAC,GAAG,EAAE,KAAK,EAAiC,EAAe,EAAE;IAC1F,OAAO,oBAAC,IAAI,QAAE,YAAY,CAAC,KAAK,IAAI,GAAG,EAAE,GAAG,EAAE,EAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAC,CAAC,CAAQ,CAAA;AAC7F,CAAC,CAAA;AAED,OAAO,EAAC,IAAI,EAAC,CAAA","sourcesContent":["import chalk from 'chalk'\nimport {Text} from 'ink'\nimport React from 'react'\nimport terminalLink from 'terminal-link'\n\ninterface Props {\n url: string\n label?: string\n}\n\nfunction fallback(text: string, url: string) {\n return `${text} ${chalk.dim(`(${url})`)}`\n}\n\n/**\n * `Link` displays a clickable link when supported by the terminal.\n */\nconst Link: React.FC<Props> = ({url, label}: React.PropsWithChildren<Props>): JSX.Element => {\n return <Text>{terminalLink(label ?? url, url, {fallback: label ? fallback : false})}</Text>\n}\n\nexport {Link}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ import { Link } from './Link.js';
2
+ import { renderString } from '../../ui.js';
3
+ import { describe, expect, test } from 'vitest';
4
+ import React from 'react';
5
+ describe('Link', async () => {
6
+ test("renders correctly with a fallback for terminals that don't support hyperlinks", async () => {
7
+ const link = {
8
+ url: 'https://example.com',
9
+ label: 'Example',
10
+ };
11
+ const { output } = renderString(React.createElement(Link, { ...link }));
12
+ expect(output).toMatchInlineSnapshot('"Example (https://example.com)"');
13
+ });
14
+ test("it doesn't render a fallback if only url is passed", async () => {
15
+ const link = {
16
+ url: 'https://example.com',
17
+ };
18
+ const { output } = renderString(React.createElement(Link, { ...link }));
19
+ expect(output).toMatchInlineSnapshot('"https://example.com"');
20
+ });
21
+ });
22
+ //# sourceMappingURL=Link.test.js.map
@@ -0,0 +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,YAAY,EAAC,MAAM,aAAa,CAAA;AACxC,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,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,MAAM,EAAC,GAAG,YAAY,CAAC,oBAAC,IAAI,OAAK,IAAI,GAAI,CAAC,CAAA;QAEjD,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,0CAA0C,CAAC,CAAA;IAClF,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,IAAI,GAAG;YACX,GAAG,EAAE,qBAAqB;SAC3B,CAAA;QAED,MAAM,EAAC,MAAM,EAAC,GAAG,YAAY,CAAC,oBAAC,IAAI,OAAK,IAAI,GAAI,CAAC,CAAA;QAEjD,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,uBAAuB,CAAC,CAAA;IAC/D,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {Link} from './Link.js'\nimport {renderString} from '../../ui.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\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 {output} = renderString(<Link {...link} />)\n\n expect(output).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 {output} = renderString(<Link {...link} />)\n\n expect(output).toMatchInlineSnapshot('\"https://example.com\"')\n })\n})\n"]}
@@ -1,7 +1,7 @@
1
1
  import { TokenItem } from './TokenizedText.js';
2
2
  import React from 'react';
3
3
  interface Props {
4
- title: string;
4
+ title?: string;
5
5
  items: TokenItem[];
6
6
  ordered?: boolean;
7
7
  }
@@ -8,10 +8,10 @@ const DOT = '•';
8
8
  */
9
9
  const List = ({ title, items, ordered = false }) => {
10
10
  return (React.createElement(Box, { flexDirection: "column" },
11
- React.createElement(Text, { dimColor: true }, title),
11
+ title && React.createElement(Text, { bold: true }, title),
12
12
  items.map((item, index) => (React.createElement(Box, { key: index },
13
13
  React.createElement(Box, null,
14
- React.createElement(Text, { dimColor: true }, ` ${ordered ? `${index + 1}.` : DOT}`)),
14
+ React.createElement(Text, null, ` ${ordered ? `${index + 1}.` : DOT}`)),
15
15
  React.createElement(Box, { flexGrow: 1, marginLeft: 1 },
16
16
  React.createElement(TokenizedText, { item: item })))))));
17
17
  };
@@ -1 +1 @@
1
- {"version":3,"file":"List.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/List.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAC3D,OAAO,EAAC,GAAG,EAAE,IAAI,EAAC,MAAM,KAAK,CAAA;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAA;AAQzB,MAAM,GAAG,GAAG,GAAG,CAAA;AAEf;;;GAGG;AACH,MAAM,IAAI,GAAoB,CAAC,EAAC,KAAK,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK,EAAiC,EAAe,EAAE;IAC7G,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ;QACzB,oBAAC,IAAI,IAAC,QAAQ,UAAE,KAAK,CAAQ;QAC5B,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC1B,oBAAC,GAAG,IAAC,GAAG,EAAE,KAAK;YACb,oBAAC,GAAG;gBACF,oBAAC,IAAI,IAAC,QAAQ,UAAE,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAQ,CAC1D;YAEN,oBAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC;gBAC7B,oBAAC,aAAa,IAAC,IAAI,EAAE,IAAI,GAAI,CACzB,CACF,CACP,CAAC,CACE,CACP,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,IAAI,EAAC,CAAA","sourcesContent":["import {TokenItem, TokenizedText} from './TokenizedText.js'\nimport {Box, Text} from 'ink'\nimport React from 'react'\n\ninterface Props {\n title: string\n items: TokenItem[]\n ordered?: boolean\n}\n\nconst DOT = '•'\n\n/**\n * `List` displays an unordered or ordered list with text aligned with the bullet point\n * and wrapped to the container width.\n */\nconst List: React.FC<Props> = ({title, items, ordered = false}: React.PropsWithChildren<Props>): JSX.Element => {\n return (\n <Box flexDirection=\"column\">\n <Text dimColor>{title}</Text>\n {items.map((item, index) => (\n <Box key={index}>\n <Box>\n <Text dimColor>{` ${ordered ? `${index + 1}.` : DOT}`}</Text>\n </Box>\n\n <Box flexGrow={1} marginLeft={1}>\n <TokenizedText item={item} />\n </Box>\n </Box>\n ))}\n </Box>\n )\n}\n\nexport {List}\n"]}
1
+ {"version":3,"file":"List.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/List.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAC3D,OAAO,EAAC,GAAG,EAAE,IAAI,EAAC,MAAM,KAAK,CAAA;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAA;AAQzB,MAAM,GAAG,GAAG,GAAG,CAAA;AAEf;;;GAGG;AACH,MAAM,IAAI,GAAoB,CAAC,EAAC,KAAK,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK,EAAC,EAAe,EAAE;IAC7E,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ;QACxB,KAAK,IAAI,oBAAC,IAAI,IAAC,IAAI,UAAE,KAAK,CAAQ;QAClC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC1B,oBAAC,GAAG,IAAC,GAAG,EAAE,KAAK;YACb,oBAAC,GAAG;gBACF,oBAAC,IAAI,QAAE,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAQ,CACjD;YAEN,oBAAC,GAAG,IAAC,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC;gBAC7B,oBAAC,aAAa,IAAC,IAAI,EAAE,IAAI,GAAI,CACzB,CACF,CACP,CAAC,CACE,CACP,CAAA;AACH,CAAC,CAAA;AAED,OAAO,EAAC,IAAI,EAAC,CAAA","sourcesContent":["import {TokenItem, TokenizedText} from './TokenizedText.js'\nimport {Box, Text} from 'ink'\nimport React from 'react'\n\ninterface Props {\n title?: string\n items: TokenItem[]\n ordered?: boolean\n}\n\nconst DOT = '•'\n\n/**\n * `List` displays an unordered or ordered list with text aligned with the bullet point\n * and wrapped to the container width.\n */\nconst List: React.FC<Props> = ({title, items, ordered = false}): JSX.Element => {\n return (\n <Box flexDirection=\"column\">\n {title && <Text bold>{title}</Text>}\n {items.map((item, index) => (\n <Box key={index}>\n <Box>\n <Text>{` ${ordered ? `${index + 1}.` : DOT}`}</Text>\n </Box>\n\n <Box flexGrow={1} marginLeft={1}>\n <TokenizedText item={item} />\n </Box>\n </Box>\n ))}\n </Box>\n )\n}\n\nexport {List}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,34 @@
1
+ import { List } from './List.js';
2
+ import { renderString } from '../../ui.js';
3
+ import { unstyled } from '../../../../output.js';
4
+ import { describe, expect, test } from 'vitest';
5
+ import React from 'react';
6
+ describe('List', async () => {
7
+ test('renders unordered items', async () => {
8
+ const options = {
9
+ title: 'List title',
10
+ items: ['Item 1', 'Item 2', 'Item 3'],
11
+ ordered: false,
12
+ };
13
+ const { output } = renderString(React.createElement(List, { ...options }));
14
+ expect(unstyled(output)).toMatchInlineSnapshot(`
15
+ "List title
16
+ • Item 1
17
+ • Item 2
18
+ • Item 3"
19
+ `);
20
+ });
21
+ test('renders ordered items', async () => {
22
+ const options = {
23
+ items: ['Item 1', 'Item 2', 'Item 3'],
24
+ ordered: true,
25
+ };
26
+ const { output } = renderString(React.createElement(List, { ...options }));
27
+ expect(unstyled(output)).toMatchInlineSnapshot(`
28
+ " 1. Item 1
29
+ 2. Item 2
30
+ 3. Item 3"
31
+ `);
32
+ });
33
+ });
34
+ //# sourceMappingURL=List.test.js.map
@@ -0,0 +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,YAAY,EAAC,MAAM,aAAa,CAAA;AACxC,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;AAEzB,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,MAAM,EAAC,GAAG,YAAY,CAAC,oBAAC,IAAI,OAAK,OAAO,GAAI,CAAC,CAAA;QAEpD,MAAM,CAAC,QAAQ,CAAC,MAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;KAK/C,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,MAAM,EAAC,GAAG,YAAY,CAAC,oBAAC,IAAI,OAAK,OAAO,GAAI,CAAC,CAAA;QAEpD,MAAM,CAAC,QAAQ,CAAC,MAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;KAI/C,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {List} from './List.js'\nimport {renderString} from '../../ui.js'\nimport {unstyled} from '../../../../output.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\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 {output} = renderString(<List {...options} />)\n\n expect(unstyled(output!)).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 {output} = renderString(<List {...options} />)\n\n expect(unstyled(output!)).toMatchInlineSnapshot(`\n \" 1. Item 1\n 2. Item 2\n 3. Item 3\"\n `)\n })\n})\n"]}
@@ -11,7 +11,19 @@ interface LinkToken {
11
11
  interface CharToken {
12
12
  char: string;
13
13
  }
14
- declare type Token = string | CommandToken | LinkToken | CharToken;
14
+ interface UserInputToken {
15
+ userInput: string;
16
+ }
17
+ interface FilePathToken {
18
+ filePath: string;
19
+ }
20
+ interface ListToken {
21
+ list: {
22
+ items: TokenItem[];
23
+ ordered?: boolean;
24
+ };
25
+ }
26
+ declare type Token = string | CommandToken | LinkToken | CharToken | UserInputToken | FilePathToken | ListToken;
15
27
  export declare type TokenItem = Token | Token[];
16
28
  interface Props {
17
29
  item: TokenItem;
@@ -1,14 +1,38 @@
1
1
  import { Command } from './Command.js';
2
2
  import { Link } from './Link.js';
3
- import { Text } from 'ink';
3
+ import { List } from './List.js';
4
+ import { UserInput } from './UserInput.js';
5
+ import { FilePath } from './FilePath.js';
6
+ import { Box, Text } from 'ink';
4
7
  import React from 'react';
8
+ function tokenToBlock(token) {
9
+ return {
10
+ display: typeof token !== 'string' && 'list' in token ? 'block' : 'inline',
11
+ value: token,
12
+ };
13
+ }
14
+ function splitByDisplayType(acc, item) {
15
+ if (item.display === 'block') {
16
+ acc.push([item]);
17
+ }
18
+ else {
19
+ const last = acc[acc.length - 1];
20
+ if (last && last[0].display === 'inline') {
21
+ last.push(item);
22
+ }
23
+ else {
24
+ acc.push([item]);
25
+ }
26
+ }
27
+ return acc;
28
+ }
5
29
  /**
6
30
  * `TokenizedText` renders a text string with tokens that can be either strings,
7
31
  * links, and commands.
8
32
  */
9
33
  const TokenizedText = ({ item }) => {
10
34
  if (typeof item === 'string') {
11
- return React.createElement(Text, { dimColor: true }, item);
35
+ return React.createElement(Text, null, item);
12
36
  }
13
37
  else if ('command' in item) {
14
38
  return React.createElement(Command, { command: item.command });
@@ -17,12 +41,29 @@ const TokenizedText = ({ item }) => {
17
41
  return React.createElement(Link, { ...item.link });
18
42
  }
19
43
  else if ('char' in item) {
20
- return React.createElement(Text, { dimColor: true }, item.char[0]);
44
+ return React.createElement(Text, null, item.char[0]);
45
+ }
46
+ else if ('userInput' in item) {
47
+ return React.createElement(UserInput, { userInput: item.userInput });
48
+ }
49
+ else if ('filePath' in item) {
50
+ return React.createElement(FilePath, { filePath: item.filePath });
51
+ }
52
+ else if ('list' in item) {
53
+ return React.createElement(List, { ...item.list });
21
54
  }
22
55
  else {
23
- return (React.createElement(Text, null, item.map((listItem, index) => (React.createElement(Text, { key: index },
24
- index !== 0 && !(typeof listItem !== 'string' && 'char' in listItem) && React.createElement(Text, null, " "),
25
- React.createElement(TokenizedText, { item: listItem }))))));
56
+ const groupedItems = item.map(tokenToBlock).reduce(splitByDisplayType, []);
57
+ return (React.createElement(Box, { flexDirection: "column" }, groupedItems.map((items, groupIndex) => {
58
+ if (items[0].display === 'inline') {
59
+ return (React.createElement(Text, { key: groupIndex }, items.map((item, itemIndex) => (React.createElement(Text, { key: itemIndex },
60
+ itemIndex !== 0 && !(typeof item.value !== 'string' && 'char' in item.value) && React.createElement(Text, null, " "),
61
+ React.createElement(TokenizedText, { item: item.value }))))));
62
+ }
63
+ else {
64
+ return React.createElement(List, { key: groupIndex, items: items[0].value.list.items });
65
+ }
66
+ })));
26
67
  }
27
68
  };
28
69
  export { TokenizedText };
@@ -1 +1 @@
1
- {"version":3,"file":"TokenizedText.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TokenizedText.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAA;AACpC,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAA;AAC9B,OAAO,EAAC,IAAI,EAAC,MAAM,KAAK,CAAA;AACxB,OAAO,KAAK,MAAM,OAAO,CAAA;AAwBzB;;;GAGG;AACH,MAAM,aAAa,GAAoB,CAAC,EAAC,IAAI,EAAC,EAAE,EAAE;IAChD,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;QAC5B,OAAO,oBAAC,IAAI,IAAC,QAAQ,UAAE,IAAI,CAAQ,CAAA;KACpC;SAAM,IAAI,SAAS,IAAI,IAAI,EAAE;QAC5B,OAAO,oBAAC,OAAO,IAAC,OAAO,EAAE,IAAI,CAAC,OAAO,GAAI,CAAA;KAC1C;SAAM,IAAI,MAAM,IAAI,IAAI,EAAE;QACzB,OAAO,oBAAC,IAAI,OAAK,IAAI,CAAC,IAAI,GAAI,CAAA;KAC/B;SAAM,IAAI,MAAM,IAAI,IAAI,EAAE;QACzB,OAAO,oBAAC,IAAI,IAAC,QAAQ,UAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAQ,CAAA;KAC5C;SAAM;QACL,OAAO,CACL,oBAAC,IAAI,QACF,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC,CAC7B,oBAAC,IAAI,IAAC,GAAG,EAAE,KAAK;YACb,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,QAAQ,KAAK,QAAQ,IAAI,MAAM,IAAI,QAAQ,CAAC,IAAI,oBAAC,IAAI,YAAS;YACvF,oBAAC,aAAa,IAAC,IAAI,EAAE,QAAQ,GAAI,CAC5B,CACR,CAAC,CACG,CACR,CAAA;KACF;AACH,CAAC,CAAA;AAED,OAAO,EAAC,aAAa,EAAC,CAAA","sourcesContent":["import {Command} from './Command.js'\nimport {Link} from './Link.js'\nimport {Text} from 'ink'\nimport React from 'react'\n\ninterface CommandToken {\n command: string\n}\n\ninterface LinkToken {\n link: {\n label?: string\n url: string\n }\n}\n\ninterface CharToken {\n char: string\n}\n\ntype Token = string | CommandToken | LinkToken | CharToken\nexport type TokenItem = Token | Token[]\n\ninterface Props {\n item: TokenItem\n}\n\n/**\n * `TokenizedText` renders a text string with tokens that can be either strings,\n * links, and commands.\n */\nconst TokenizedText: React.FC<Props> = ({item}) => {\n if (typeof item === 'string') {\n return <Text dimColor>{item}</Text>\n } else if ('command' in item) {\n return <Command command={item.command} />\n } else if ('link' in item) {\n return <Link {...item.link} />\n } else if ('char' in item) {\n return <Text dimColor>{item.char[0]}</Text>\n } else {\n return (\n <Text>\n {item.map((listItem, index) => (\n <Text key={index}>\n {index !== 0 && !(typeof listItem !== 'string' && 'char' in listItem) && <Text> </Text>}\n <TokenizedText item={listItem} />\n </Text>\n ))}\n </Text>\n )\n }\n}\n\nexport {TokenizedText}\n"]}
1
+ {"version":3,"file":"TokenizedText.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TokenizedText.tsx"],"names":[],"mappings":"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","sourcesContent":["import {Command} from './Command.js'\nimport {Link} from './Link.js'\nimport {List} from './List.js'\nimport {UserInput} from './UserInput.js'\nimport {FilePath} from './FilePath.js'\nimport {Box, Text} from 'ink'\nimport React from 'react'\n\ninterface CommandToken {\n command: string\n}\n\ninterface LinkToken {\n link: {\n label?: string\n url: string\n }\n}\n\ninterface CharToken {\n char: string\n}\n\ninterface UserInputToken {\n userInput: string\n}\n\ninterface FilePathToken {\n filePath: string\n}\n\ninterface ListToken {\n list: {\n items: TokenItem[]\n ordered?: boolean\n }\n}\n\ntype Token = string | CommandToken | LinkToken | CharToken | UserInputToken | FilePathToken | ListToken\nexport type TokenItem = Token | Token[]\n\ntype DisplayType = 'block' | 'inline'\ninterface Block {\n display: DisplayType\n value: Token\n}\n\nfunction tokenToBlock(token: Token): Block {\n return {\n display: typeof token !== 'string' && 'list' in token ? 'block' : 'inline',\n value: token,\n }\n}\n\nfunction splitByDisplayType(acc: Block[][], item: Block) {\n if (item.display === 'block') {\n acc.push([item])\n } else {\n const last = acc[acc.length - 1]\n if (last && last[0]!.display === 'inline') {\n last.push(item)\n } else {\n acc.push([item])\n }\n }\n return acc\n}\n\ninterface Props {\n item: TokenItem\n}\n\n/**\n * `TokenizedText` renders a text string with tokens that can be either strings,\n * links, and commands.\n */\nconst TokenizedText: React.FC<Props> = ({item}) => {\n if (typeof item === 'string') {\n return <Text>{item}</Text>\n } else if ('command' in item) {\n return <Command command={item.command} />\n } else if ('link' in item) {\n return <Link {...item.link} />\n } else if ('char' in item) {\n return <Text>{item.char[0]}</Text>\n } else if ('userInput' in item) {\n return <UserInput userInput={item.userInput} />\n } else if ('filePath' in item) {\n return <FilePath filePath={item.filePath} />\n } else if ('list' in item) {\n return <List {...item.list} />\n } else {\n const groupedItems = item.map(tokenToBlock).reduce(splitByDisplayType, [])\n\n return (\n <Box flexDirection=\"column\">\n {groupedItems.map((items, groupIndex) => {\n if (items[0]!.display === 'inline') {\n return (\n <Text key={groupIndex}>\n {items.map((item, itemIndex) => (\n <Text key={itemIndex}>\n {itemIndex !== 0 && !(typeof item.value !== 'string' && 'char' in item.value) && <Text> </Text>}\n <TokenizedText item={item.value} />\n </Text>\n ))}\n </Text>\n )\n } else {\n return <List key={groupIndex} items={(items[0]!.value as ListToken).list.items} />\n }\n })}\n </Box>\n )\n }\n}\n\nexport {TokenizedText}\n"]}
@@ -0,0 +1,44 @@
1
+ import { TokenizedText } from './TokenizedText.js';
2
+ import { renderString } from '../../ui.js';
3
+ import { unstyled } from '../../../../output.js';
4
+ import { describe, expect, test } from 'vitest';
5
+ import React from 'react';
6
+ describe('TokenizedText', async () => {
7
+ test('renders arrays of items separated by spaces', async () => {
8
+ const item = [
9
+ 'Run',
10
+ {
11
+ command: 'cd verification-app',
12
+ },
13
+ {
14
+ link: {
15
+ url: 'https://example.com',
16
+ label: 'Example',
17
+ },
18
+ },
19
+ {
20
+ char: '!',
21
+ },
22
+ {
23
+ userInput: 'my-app',
24
+ },
25
+ {
26
+ list: {
27
+ items: ['Item 1', 'Item 2', 'Item 3'],
28
+ },
29
+ },
30
+ {
31
+ filePath: 'src/this/is/a/test.js',
32
+ },
33
+ ];
34
+ const { output } = renderString(React.createElement(TokenizedText, { item: item }));
35
+ expect(unstyled(output)).toMatchInlineSnapshot(`
36
+ "Run \`cd verification-app\` Example (https://example.com)! my-app
37
+ • Item 1
38
+ • Item 2
39
+ • Item 3
40
+ \\"src/this/is/a/test.js\\""
41
+ `);
42
+ });
43
+ });
44
+ //# sourceMappingURL=TokenizedText.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TokenizedText.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TokenizedText.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAC,YAAY,EAAC,MAAM,aAAa,CAAA;AACxC,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;AAEzB,QAAQ,CAAC,eAAe,EAAE,KAAK,IAAI,EAAE;IACnC,IAAI,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,IAAI,GAAG;YACX,KAAK;YACL;gBACE,OAAO,EAAE,qBAAqB;aAC/B;YACD;gBACE,IAAI,EAAE;oBACJ,GAAG,EAAE,qBAAqB;oBAC1B,KAAK,EAAE,SAAS;iBACjB;aACF;YACD;gBACE,IAAI,EAAE,GAAG;aACV;YACD;gBACE,SAAS,EAAE,QAAQ;aACpB;YACD;gBACE,IAAI,EAAE;oBACJ,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;iBACtC;aACF;YACD;gBACE,QAAQ,EAAE,uBAAuB;aAClC;SACF,CAAA;QAED,MAAM,EAAC,MAAM,EAAC,GAAG,YAAY,CAAC,oBAAC,aAAa,IAAC,IAAI,EAAE,IAAI,GAAI,CAAC,CAAA;QAE5D,MAAM,CAAC,QAAQ,CAAC,MAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC;;;;;;KAM/C,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {TokenizedText} from './TokenizedText.js'\nimport {renderString} from '../../ui.js'\nimport {unstyled} from '../../../../output.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\n\ndescribe('TokenizedText', async () => {\n test('renders arrays of items separated by spaces', async () => {\n const item = [\n 'Run',\n {\n command: 'cd verification-app',\n },\n {\n link: {\n url: 'https://example.com',\n label: 'Example',\n },\n },\n {\n char: '!',\n },\n {\n userInput: 'my-app',\n },\n {\n list: {\n items: ['Item 1', 'Item 2', 'Item 3'],\n },\n },\n {\n filePath: 'src/this/is/a/test.js',\n },\n ]\n\n const {output} = renderString(<TokenizedText item={item} />)\n\n expect(unstyled(output!)).toMatchInlineSnapshot(`\n \"Run \\`cd verification-app\\` Example (https://example.com)! my-app\n • Item 1\n • Item 2\n • Item 3\n \\\\\"src/this/is/a/test.js\\\\\"\"\n `)\n })\n})\n"]}
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ interface Props {
3
+ userInput: string;
4
+ }
5
+ /**
6
+ * `UserInput` displays some text that represents input from the user.
7
+ * For example an answer to a selection prompt.
8
+ */
9
+ declare const UserInput: React.FC<Props>;
10
+ export { UserInput };
@@ -0,0 +1,11 @@
1
+ import { Text } from 'ink';
2
+ import React from 'react';
3
+ /**
4
+ * `UserInput` displays some text that represents input from the user.
5
+ * For example an answer to a selection prompt.
6
+ */
7
+ const UserInput = ({ userInput }) => {
8
+ return React.createElement(Text, { color: "cyan" }, userInput);
9
+ };
10
+ export { UserInput };
11
+ //# sourceMappingURL=UserInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserInput.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/UserInput.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,KAAK,CAAA;AACxB,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB;;;GAGG;AACH,MAAM,SAAS,GAAoB,CAAC,EAAC,SAAS,EAAiC,EAAe,EAAE;IAC9F,OAAO,oBAAC,IAAI,IAAC,KAAK,EAAC,MAAM,IAAE,SAAS,CAAQ,CAAA;AAC9C,CAAC,CAAA;AAED,OAAO,EAAC,SAAS,EAAC,CAAA","sourcesContent":["import {Text} from 'ink'\nimport React from 'react'\n\ninterface Props {\n userInput: string\n}\n\n/**\n * `UserInput` displays some text that represents input from the user.\n * For example an answer to a selection prompt.\n */\nconst UserInput: React.FC<Props> = ({userInput}: React.PropsWithChildren<Props>): JSX.Element => {\n return <Text color=\"cyan\">{userInput}</Text>\n}\n\nexport {UserInput}\n"]}
@@ -0,0 +1,11 @@
1
+ import { UserInput } from './UserInput.js';
2
+ import { renderString } from '../../ui.js';
3
+ import { describe, expect, test } from 'vitest';
4
+ import React from 'react';
5
+ describe('UserInput', async () => {
6
+ test('renders correctly', async () => {
7
+ const { output } = renderString(React.createElement(UserInput, { userInput: "my-app" }));
8
+ expect(output).toMatchInlineSnapshot('"my-app"');
9
+ });
10
+ });
11
+ //# sourceMappingURL=UserInput.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UserInput.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/UserInput.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAC,YAAY,EAAC,MAAM,aAAa,CAAA;AACxC,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAC,MAAM,QAAQ,CAAA;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,QAAQ,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE;IAC/B,IAAI,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,EAAC,MAAM,EAAC,GAAG,YAAY,CAAC,oBAAC,SAAS,IAAC,SAAS,EAAC,QAAQ,GAAG,CAAC,CAAA;QAE/D,MAAM,CAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,oBAAoB,CAAC,CAAA;IAC5D,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import {UserInput} from './UserInput.js'\nimport {renderString} from '../../ui.js'\nimport {describe, expect, test} from 'vitest'\nimport React from 'react'\n\ndescribe('UserInput', async () => {\n test('renders correctly', async () => {\n const {output} = renderString(<UserInput userInput=\"my-app\" />)\n\n expect(output).toMatchInlineSnapshot('\"\u001b[36mmy-app\u001b[39m\"')\n })\n})\n"]}
@@ -0,0 +1,50 @@
1
+ import { Result } from './result.js';
2
+ export interface GithubRelease {
3
+ id: number;
4
+ url: string;
5
+ tag_name: string;
6
+ name: string;
7
+ body: string;
8
+ draft: boolean;
9
+ prerelease: boolean;
10
+ created_at: string;
11
+ published_at: string;
12
+ tarball_url: string;
13
+ }
14
+ interface GetLatestGitHubReleaseOptions {
15
+ filter: (release: GithubRelease) => boolean;
16
+ }
17
+ /**
18
+ * Given a GitHub repository it obtains the latest release.
19
+ * @param owner - Repository owner (e.g., shopify)
20
+ * @param repo - Repository name (e.g., cli)
21
+ * @param options - Options
22
+ */
23
+ export declare function getLatestGitHubRelease(owner: string, repo: string, options?: GetLatestGitHubReleaseOptions): Promise<GithubRelease>;
24
+ interface ParseRepositoryURLOutput {
25
+ full: string;
26
+ site: string;
27
+ user: string;
28
+ name: string;
29
+ ref: string;
30
+ subDirectory: string;
31
+ ssh: string;
32
+ http: string;
33
+ }
34
+ /**
35
+ * Given a GitHub repository URL, it parses it and returns its coomponents.
36
+ * @param url - The GitHub repository URL
37
+ */
38
+ export declare function parseGitHubRepositoryURL(url: string): Result<ParseRepositoryURLOutput, Error>;
39
+ export interface GithubRepositoryReference {
40
+ baseURL: string;
41
+ branch?: string;
42
+ filePath?: string;
43
+ }
44
+ /**
45
+ * Given a GitHub repository URL it parses it and extracts the branch, file path,
46
+ * and base URL components
47
+ * @param reference - A GitHub repository URL (e.g. https://github.com/Shopify/cli/blob/main/package.json)
48
+ */
49
+ export declare function parseGitHubRepositoryReference(reference: string): GithubRepositoryReference;
50
+ export {};