@shopify/cli-kit 4.6.1 → 4.7.1

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 (164) hide show
  1. package/dist/private/node/analytics/bounded-collections.js +1 -4
  2. package/dist/private/node/analytics/bounded-collections.js.map +1 -1
  3. package/dist/private/node/analytics/graphql-error-codes.d.ts +2 -2
  4. package/dist/private/node/analytics/graphql-error-codes.js +2 -2
  5. package/dist/private/node/analytics/graphql-error-codes.js.map +1 -1
  6. package/dist/private/node/analytics.js +12 -7
  7. package/dist/private/node/analytics.js.map +1 -1
  8. package/dist/private/node/api/headers.js +3 -0
  9. package/dist/private/node/api/headers.js.map +1 -1
  10. package/dist/private/node/api.js +8 -8
  11. package/dist/private/node/api.js.map +1 -1
  12. package/dist/private/node/conf-store.js +1 -1
  13. package/dist/private/node/conf-store.js.map +1 -1
  14. package/dist/private/node/content-tokens.js +27 -2
  15. package/dist/private/node/content-tokens.js.map +1 -1
  16. package/dist/private/node/otel-metrics.d.ts +1 -1
  17. package/dist/private/node/otel-metrics.js +5 -2
  18. package/dist/private/node/otel-metrics.js.map +1 -1
  19. package/dist/private/node/plugin-hints.d.ts +16 -0
  20. package/dist/private/node/plugin-hints.js +29 -0
  21. package/dist/private/node/plugin-hints.js.map +1 -0
  22. package/dist/private/node/request-ids.js +2 -3
  23. package/dist/private/node/request-ids.js.map +1 -1
  24. package/dist/private/node/session/device-authorization.js +4 -7
  25. package/dist/private/node/session/device-authorization.js.map +1 -1
  26. package/dist/private/node/session/exchange.d.ts +4 -4
  27. package/dist/private/node/session/exchange.js +21 -5
  28. package/dist/private/node/session/exchange.js.map +1 -1
  29. package/dist/private/node/testing/ui.js +18 -19
  30. package/dist/private/node/testing/ui.js.map +1 -1
  31. package/dist/private/node/ui/components/Alert.d.ts +1 -1
  32. package/dist/private/node/ui/components/Alert.js.map +1 -1
  33. package/dist/private/node/ui/components/ConcurrentOutput.test.js +2 -0
  34. package/dist/private/node/ui/components/ConcurrentOutput.test.js.map +1 -1
  35. package/dist/private/node/ui/components/DangerousConfirmationPrompt.d.ts +1 -1
  36. package/dist/private/node/ui/components/DangerousConfirmationPrompt.js.map +1 -1
  37. package/dist/private/node/ui/components/List.d.ts +1 -1
  38. package/dist/private/node/ui/components/List.js.map +1 -1
  39. package/dist/private/node/ui/components/Prompts/InfoMessage.d.ts +1 -1
  40. package/dist/private/node/ui/components/Prompts/InfoMessage.js.map +1 -1
  41. package/dist/private/node/ui/components/Prompts/InfoTable.d.ts +1 -1
  42. package/dist/private/node/ui/components/Prompts/InfoTable.js.map +1 -1
  43. package/dist/private/node/ui/components/Prompts/PromptLayout.d.ts +1 -1
  44. package/dist/private/node/ui/components/Prompts/PromptLayout.js.map +1 -1
  45. package/dist/private/node/ui/components/SingleTask.test.js +1 -0
  46. package/dist/private/node/ui/components/SingleTask.test.js.map +1 -1
  47. package/dist/private/node/ui/components/TabularData.d.ts +1 -1
  48. package/dist/private/node/ui/components/TabularData.js +2 -1
  49. package/dist/private/node/ui/components/TabularData.js.map +1 -1
  50. package/dist/private/node/ui/components/TextPrompt.d.ts +1 -1
  51. package/dist/private/node/ui/components/TextPrompt.js.map +1 -1
  52. package/dist/private/node/ui/components/TokenizedText.d.ts +1 -38
  53. package/dist/private/node/ui/components/TokenizedText.js +0 -54
  54. package/dist/private/node/ui/components/TokenizedText.js.map +1 -1
  55. package/dist/private/node/ui/components/TokenizedText.test.js +2 -1
  56. package/dist/private/node/ui/components/TokenizedText.test.js.map +1 -1
  57. package/dist/private/node/ui/components/token-item.d.ts +38 -0
  58. package/dist/private/node/ui/components/token-item.js +63 -0
  59. package/dist/private/node/ui/components/token-item.js.map +1 -0
  60. package/dist/private/node/ui/hooks/use-abort-signal.js +5 -4
  61. package/dist/private/node/ui/hooks/use-abort-signal.js.map +1 -1
  62. package/dist/private/node/ui/hooks/use-select-state.js +2 -1
  63. package/dist/private/node/ui/hooks/use-select-state.js.map +1 -1
  64. package/dist/private/node/ui/utilities.d.ts +6 -6
  65. package/dist/private/node/ui/utilities.js +1 -1
  66. package/dist/private/node/ui/utilities.js.map +1 -1
  67. package/dist/private/node/ui.js +18 -15
  68. package/dist/private/node/ui.js.map +1 -1
  69. package/dist/public/common/string.d.ts +1 -1
  70. package/dist/public/common/string.js.map +1 -1
  71. package/dist/public/common/version.d.ts +1 -1
  72. package/dist/public/common/version.js +1 -1
  73. package/dist/public/common/version.js.map +1 -1
  74. package/dist/public/node/abort.d.ts +14 -6
  75. package/dist/public/node/abort.js +7 -6
  76. package/dist/public/node/abort.js.map +1 -1
  77. package/dist/public/node/analytics.d.ts +1 -0
  78. package/dist/public/node/analytics.js +79 -32
  79. package/dist/public/node/analytics.js.map +1 -1
  80. package/dist/public/node/api/admin.js +1 -1
  81. package/dist/public/node/api/admin.js.map +1 -1
  82. package/dist/public/node/base-command.d.ts +10 -0
  83. package/dist/public/node/base-command.js +31 -8
  84. package/dist/public/node/base-command.js.map +1 -1
  85. package/dist/public/node/cli.d.ts +13 -0
  86. package/dist/public/node/cli.js +18 -2
  87. package/dist/public/node/cli.js.map +1 -1
  88. package/dist/public/node/context/local.d.ts +3 -1
  89. package/dist/public/node/context/local.js +14 -7
  90. package/dist/public/node/context/local.js.map +1 -1
  91. package/dist/public/node/custom-oclif-loader.js +19 -16
  92. package/dist/public/node/custom-oclif-loader.js.map +1 -1
  93. package/dist/public/node/doctor/framework.js +4 -5
  94. package/dist/public/node/doctor/framework.js.map +1 -1
  95. package/dist/public/node/environment.js +8 -11
  96. package/dist/public/node/environment.js.map +1 -1
  97. package/dist/public/node/error.d.ts +1 -4
  98. package/dist/public/node/error.js +20 -7
  99. package/dist/public/node/error.js.map +1 -1
  100. package/dist/public/node/git.js +7 -5
  101. package/dist/public/node/git.js.map +1 -1
  102. package/dist/public/node/global-context.js +1 -1
  103. package/dist/public/node/global-context.js.map +1 -1
  104. package/dist/public/node/hidden-folder.js +2 -4
  105. package/dist/public/node/hidden-folder.js.map +1 -1
  106. package/dist/public/node/hooks/postrun.js +1 -1
  107. package/dist/public/node/hooks/postrun.js.map +1 -1
  108. package/dist/public/node/hooks/prerun.js +5 -1
  109. package/dist/public/node/hooks/prerun.js.map +1 -1
  110. package/dist/public/node/local-storage.js +1 -0
  111. package/dist/public/node/local-storage.js.map +1 -1
  112. package/dist/public/node/metadata.d.ts +3 -0
  113. package/dist/public/node/metadata.js.map +1 -1
  114. package/dist/public/node/mimes.js +1 -3
  115. package/dist/public/node/mimes.js.map +1 -1
  116. package/dist/public/node/node-package-manager.js +31 -73
  117. package/dist/public/node/node-package-manager.js.map +1 -1
  118. package/dist/public/node/notifications-system.js +19 -3
  119. package/dist/public/node/notifications-system.js.map +1 -1
  120. package/dist/public/node/os.js +5 -10
  121. package/dist/public/node/os.js.map +1 -1
  122. package/dist/public/node/output.js +11 -20
  123. package/dist/public/node/output.js.map +1 -1
  124. package/dist/public/node/plugins/tunnel.d.ts +1 -2
  125. package/dist/public/node/plugins/tunnel.js +2 -2
  126. package/dist/public/node/plugins/tunnel.js.map +1 -1
  127. package/dist/public/node/result.js +4 -2
  128. package/dist/public/node/result.js.map +1 -1
  129. package/dist/public/node/serial-batch-processor.js +4 -3
  130. package/dist/public/node/serial-batch-processor.js.map +1 -1
  131. package/dist/public/node/store-auth-session.js +1 -1
  132. package/dist/public/node/store-auth-session.js.map +1 -1
  133. package/dist/public/node/system.d.ts +15 -1
  134. package/dist/public/node/system.js +42 -6
  135. package/dist/public/node/system.js.map +1 -1
  136. package/dist/public/node/themes/conf.js +2 -2
  137. package/dist/public/node/themes/conf.js.map +1 -1
  138. package/dist/public/node/themes/factories.js +2 -2
  139. package/dist/public/node/themes/factories.js.map +1 -1
  140. package/dist/public/node/themes/theme-manager.js +2 -0
  141. package/dist/public/node/themes/theme-manager.js.map +1 -1
  142. package/dist/public/node/themes/urls.js +7 -7
  143. package/dist/public/node/themes/urls.js.map +1 -1
  144. package/dist/public/node/toml/toml-file.js +12 -13
  145. package/dist/public/node/toml/toml-file.js.map +1 -1
  146. package/dist/public/node/ui.d.ts +1 -1
  147. package/dist/public/node/ui.js +1 -1
  148. package/dist/public/node/ui.js.map +1 -1
  149. package/dist/public/node/vendor/dev_server/dev-server-2024.js +14 -2
  150. package/dist/public/node/vendor/dev_server/dev-server-2024.js.map +1 -1
  151. package/dist/public/node/vendor/dev_server/dev-server.js +3 -0
  152. package/dist/public/node/vendor/dev_server/dev-server.js.map +1 -1
  153. package/dist/public/node/vendor/dev_server/network/index.js +1 -1
  154. package/dist/public/node/vendor/dev_server/network/index.js.map +1 -1
  155. package/dist/public/node/vendor/otel-js/export/InstantaneousMetricReader.js +1 -0
  156. package/dist/public/node/vendor/otel-js/export/InstantaneousMetricReader.js.map +1 -1
  157. package/dist/public/node/vendor/otel-js/service/BaseOtelService/BaseOtelService.js +5 -2
  158. package/dist/public/node/vendor/otel-js/service/BaseOtelService/BaseOtelService.js.map +1 -1
  159. package/dist/public/node/vendor/otel-js/service/types.d.ts +2 -2
  160. package/dist/public/node/vendor/otel-js/service/types.js.map +1 -1
  161. package/dist/public/node/vscode.js +12 -11
  162. package/dist/public/node/vscode.js.map +1 -1
  163. package/dist/tsconfig.tsbuildinfo +1 -1
  164. package/package.json +3 -9
@@ -13,60 +13,6 @@ function tokenToBlock(token) {
13
13
  value: token,
14
14
  };
15
15
  }
16
- export function tokenItemToString(token) {
17
- if (typeof token === 'string') {
18
- return token;
19
- }
20
- else if ('command' in token) {
21
- return token.command;
22
- }
23
- else if ('link' in token) {
24
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- empty label should fall through to url
25
- return token.link.label || token.link.url;
26
- }
27
- else if ('char' in token) {
28
- return token.char;
29
- }
30
- else if ('userInput' in token) {
31
- return token.userInput;
32
- }
33
- else if ('subdued' in token) {
34
- return token.subdued;
35
- }
36
- else if ('filePath' in token) {
37
- return token.filePath;
38
- }
39
- else if ('list' in token) {
40
- return token.list.items.map(tokenItemToString).join(' ');
41
- }
42
- else if ('bold' in token) {
43
- return token.bold;
44
- }
45
- else if ('info' in token) {
46
- return token.info;
47
- }
48
- else if ('warn' in token) {
49
- return token.warn;
50
- }
51
- else if ('error' in token) {
52
- return token.error;
53
- }
54
- else {
55
- return token
56
- .map((item, index) => {
57
- if (index !== 0 && !(typeof item !== 'string' && 'char' in item)) {
58
- return ` ${tokenItemToString(item)}`;
59
- }
60
- else {
61
- return tokenItemToString(item);
62
- }
63
- })
64
- .join('');
65
- }
66
- }
67
- export function appendToTokenItem(token, suffix) {
68
- return Array.isArray(token) ? [...token, { char: suffix }] : [token, { char: suffix }];
69
- }
70
16
  function splitByDisplayType(acc, item) {
71
17
  if (item.display === 'block') {
72
18
  acc.push([item]);
@@ -1 +1 @@
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 {Subdued} from './Subdued.js'\nimport {LinksContext} from '../contexts/LinksContext.js'\nimport React, {FunctionComponent, useContext} from 'react'\nimport {Box, Text} from 'ink'\n\nexport interface LinkToken {\n link: {\n label?: string\n url: string\n }\n}\n\nexport interface UserInputToken {\n userInput: string\n}\n\nexport interface ListToken {\n list: {\n title?: TokenItem<InlineToken>\n items: TokenItem<InlineToken>[]\n ordered?: boolean\n }\n}\n\nexport interface BoldToken {\n bold: string\n}\n\nexport type Token =\n | string\n | {\n command: string\n }\n | LinkToken\n | {\n char: string\n }\n | UserInputToken\n | {\n subdued: string\n }\n | {\n filePath: string\n }\n | ListToken\n | BoldToken\n | {\n info: string\n }\n | {\n warn: string\n }\n | {\n error: string\n }\n\nexport type InlineToken = Exclude<Token, ListToken>\nexport type TokenItem<T extends Token = Token> = T | T[]\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\nexport function tokenItemToString(token: TokenItem): string {\n if (typeof token === 'string') {\n return token\n } else if ('command' in token) {\n return token.command\n } else if ('link' in token) {\n // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- empty label should fall through to url\n return token.link.label || token.link.url\n } else if ('char' in token) {\n return token.char\n } else if ('userInput' in token) {\n return token.userInput\n } else if ('subdued' in token) {\n return token.subdued\n } else if ('filePath' in token) {\n return token.filePath\n } else if ('list' in token) {\n return token.list.items.map(tokenItemToString).join(' ')\n } else if ('bold' in token) {\n return token.bold\n } else if ('info' in token) {\n return token.info\n } else if ('warn' in token) {\n return token.warn\n } else if ('error' in token) {\n return token.error\n } else {\n return token\n .map((item, index) => {\n if (index !== 0 && !(typeof item !== 'string' && 'char' in item)) {\n return ` ${tokenItemToString(item)}`\n } else {\n return tokenItemToString(item)\n }\n })\n .join('')\n }\n}\n\nexport function appendToTokenItem(token: TokenItem, suffix: string): TokenItem {\n return Array.isArray(token) ? [...token, {char: suffix}] : [token, {char: suffix}]\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\nconst InlineBlocks: React.FC<{blocks: Block[]}> = ({blocks}) => {\n return (\n <Text>\n {blocks.map((block, blockIndex) => (\n <Text key={blockIndex}>\n {blockIndex !== 0 && !(typeof block.value !== 'string' && 'char' in block.value) && <Text> </Text>}\n <TokenizedText item={block.value} />\n </Text>\n ))}\n </Text>\n )\n}\n\ninterface TokenizedTextProps {\n item: TokenItem\n}\n\n// Matches CommonMark inline links of the form `[label](url)` and autolinks of\n// the form `<url>`. We deliberately require an explicit `http://` or\n// `https://` scheme on the URL so callers can't accidentally trigger\n// linkification by typing square brackets or angle brackets in plain prose.\n//\n// The URL portion forbids whitespace, the closing delimiter (`)` or `>`), and\n// `<` to keep parsing predictable. URLs that legitimately contain those\n// characters (e.g. balanced parens) must be percent-encoded by the caller —\n// per CommonMark §6.3 / §6.4.\nconst MARKDOWN_LINK_REGEX = /\\[([^[\\]]+)\\]\\((https?:\\/\\/[^()<>\\s]+)\\)|<(https?:\\/\\/[^<>\\s]+)>/g\n\n/**\n * Parses an opt-in CommonMark link or autolink from a plain string token and\n * routes the result through the existing `<Link>` component.\n *\n * Why opt-in rather than auto-detection: server-returned error strings can\n * legitimately contain URL-shaped substrings that are not meant to be\n * clickable (e.g. a tunnel-URL validation error echoing back the user's bad\n * input). Requiring the explicit `[label](url)` / `<url>` shape lets the\n * source of the message (server or client) declare intent, and keeps prose\n * with bare URLs untouched.\n *\n * Only invoked when a `LinksContext` is present (i.e. inside a Banner /\n * Alert / FatalError); outside of that, the underlying `<Link>` would render\n * the URL inline and we'd defeat the wrap-resistance the footnote mechanism\n * provides.\n */\nfunction renderStringWithMarkdownLinks(str: string): JSX.Element {\n const matches = Array.from(str.matchAll(MARKDOWN_LINK_REGEX))\n if (matches.length === 0) {\n return <Text>{str}</Text>\n }\n\n const parts: JSX.Element[] = []\n let cursor = 0\n matches.forEach((match, index) => {\n const start = match.index\n if (start === undefined) {\n return\n }\n const end = start + match[0].length\n if (start > cursor) {\n parts.push(<Text key={`t${index}`}>{str.slice(cursor, start)}</Text>)\n }\n // `[label](url)` captures label in group 1 and url in group 2;\n // `<url>` autolinks capture only the url in group 3.\n const label = match[1]\n const url = match[2] ?? match[3]\n if (url === undefined) {\n return\n }\n parts.push(<Link key={`l${index}`} label={label} url={url} />)\n cursor = end\n })\n if (cursor < str.length) {\n parts.push(<Text key=\"tail\">{str.slice(cursor)}</Text>)\n }\n return <Text>{parts}</Text>\n}\n\n/**\n * `TokenizedText` renders a text string with tokens that can be either strings,\n * links, and commands.\n */\nconst TokenizedText: FunctionComponent<TokenizedTextProps> = ({item}) => {\n const linksContext = useContext(LinksContext)\n if (typeof item === 'string') {\n return linksContext === null ? <Text>{item}</Text> : renderStringWithMarkdownLinks(item)\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 ('subdued' in item) {\n return <Subdued subdued={item.subdued} />\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 if ('bold' in item) {\n return <Text bold>{item.bold}</Text>\n } else if ('info' in item) {\n return <Text color=\"blue\">{item.info}</Text>\n } else if ('warn' in item) {\n return <Text color=\"yellow\">{item.warn}</Text>\n } else if ('error' in item) {\n return <Text color=\"red\">{item.error}</Text>\n } else {\n const groupedItems = item.map(tokenToBlock).reduce(splitByDisplayType, [])\n\n return groupedItems.length === 1 && groupedItems[0]!.every((item) => item.display === 'inline') ? (\n <InlineBlocks blocks={groupedItems[0]!} />\n ) : (\n <Box flexDirection=\"column\">\n {groupedItems.map((items, groupIndex) => {\n if (items[0]!.display === 'inline') {\n return <InlineBlocks blocks={items} key={groupIndex} />\n } else {\n return <List key={groupIndex} {...(items[0]!.value as ListToken).list} />\n }\n })}\n </Box>\n )\n }\n}\n\nexport {TokenizedText}\n"]}
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,WAAW,CAAA;AAC9B,OAAO,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAC,QAAQ,EAAC,MAAM,eAAe,CAAA;AACtC,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAA;AACpC,OAAO,EAAC,YAAY,EAAC,MAAM,6BAA6B,CAAA;AACxD,OAAO,KAAK,EAAE,EAAoB,UAAU,EAAC,MAAM,OAAO,CAAA;AAC1D,OAAO,EAAC,GAAG,EAAE,IAAI,EAAC,MAAM,KAAK,CAAA;AAU7B,SAAS,YAAY,CAAC,KAAY;IAChC,OAAO;QACL,OAAO,EAAE,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;QAC1E,KAAK,EAAE,KAAK;KACb,CAAA;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAc,EAAE,IAAW;IACrD,IAAI,IAAI,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;QAC7B,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;IAClB,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QAChC,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,CAAE,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC1C,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjB,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QAClB,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,YAAY,GAAgC,CAAC,EAAC,MAAM,EAAC,EAAE,EAAE;IAC7D,OAAO,CACL,oBAAC,IAAI,QACF,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC,CACjC,oBAAC,IAAI,IAAC,GAAG,EAAE,UAAU;QAClB,UAAU,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,oBAAC,IAAI,YAAS;QAClG,oBAAC,aAAa,IAAC,IAAI,EAAE,KAAK,CAAC,KAAK,GAAI,CAC/B,CACR,CAAC,CACG,CACR,CAAA;AACH,CAAC,CAAA;AAMD,8EAA8E;AAC9E,qEAAqE;AACrE,qEAAqE;AACrE,4EAA4E;AAC5E,EAAE;AACF,8EAA8E;AAC9E,wEAAwE;AACxE,4EAA4E;AAC5E,8BAA8B;AAC9B,MAAM,mBAAmB,GAAG,mEAAmE,CAAA;AAE/F;;;;;;;;;;;;;;;GAeG;AACH,SAAS,6BAA6B,CAAC,GAAW;IAChD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAA;IAC7D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,oBAAC,IAAI,QAAE,GAAG,CAAQ,CAAA;IAC3B,CAAC;IAED,MAAM,KAAK,GAAkB,EAAE,CAAA;IAC/B,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAC/B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAA;QACzB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAM;QACR,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;QACnC,IAAI,KAAK,GAAG,MAAM,EAAE,CAAC;YACnB,KAAK,CAAC,IAAI,CAAC,oBAAC,IAAI,IAAC,GAAG,EAAE,IAAI,KAAK,EAAE,IAAG,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAQ,CAAC,CAAA;QACvE,CAAC;QACD,+DAA+D;QAC/D,qDAAqD;QACrD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QACtB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAA;QAChC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,OAAM;QACR,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,oBAAC,IAAI,IAAC,GAAG,EAAE,IAAI,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,GAAI,CAAC,CAAA;QAC9D,MAAM,GAAG,GAAG,CAAA;IACd,CAAC,CAAC,CAAA;IACF,IAAI,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,oBAAC,IAAI,IAAC,GAAG,EAAC,MAAM,IAAE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAQ,CAAC,CAAA;IACzD,CAAC;IACD,OAAO,oBAAC,IAAI,QAAE,KAAK,CAAQ,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,aAAa,GAA0C,CAAC,EAAC,IAAI,EAAC,EAAE,EAAE;IACtE,MAAM,YAAY,GAAG,UAAU,CAAC,YAAY,CAAC,CAAA;IAC7C,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,oBAAC,IAAI,QAAE,IAAI,CAAQ,CAAC,CAAC,CAAC,6BAA6B,CAAC,IAAI,CAAC,CAAA;IAC1F,CAAC;SAAM,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;QAC7B,OAAO,oBAAC,OAAO,IAAC,OAAO,EAAE,IAAI,CAAC,OAAO,GAAI,CAAA;IAC3C,CAAC;SAAM,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QAC1B,OAAO,oBAAC,IAAI,OAAK,IAAI,CAAC,IAAI,GAAI,CAAA;IAChC,CAAC;SAAM,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QAC1B,OAAO,oBAAC,IAAI,QAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAQ,CAAA;IACpC,CAAC;SAAM,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;QAC/B,OAAO,oBAAC,SAAS,IAAC,SAAS,EAAE,IAAI,CAAC,SAAS,GAAI,CAAA;IACjD,CAAC;SAAM,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;QAC7B,OAAO,oBAAC,OAAO,IAAC,OAAO,EAAE,IAAI,CAAC,OAAO,GAAI,CAAA;IAC3C,CAAC;SAAM,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;QAC9B,OAAO,oBAAC,QAAQ,IAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,GAAI,CAAA;IAC9C,CAAC;SAAM,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QAC1B,OAAO,oBAAC,IAAI,OAAK,IAAI,CAAC,IAAI,GAAI,CAAA;IAChC,CAAC;SAAM,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QAC1B,OAAO,oBAAC,IAAI,IAAC,IAAI,UAAE,IAAI,CAAC,IAAI,CAAQ,CAAA;IACtC,CAAC;SAAM,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QAC1B,OAAO,oBAAC,IAAI,IAAC,KAAK,EAAC,MAAM,IAAE,IAAI,CAAC,IAAI,CAAQ,CAAA;IAC9C,CAAC;SAAM,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QAC1B,OAAO,oBAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,IAAE,IAAI,CAAC,IAAI,CAAQ,CAAA;IAChD,CAAC;SAAM,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QAC3B,OAAO,oBAAC,IAAI,IAAC,KAAK,EAAC,KAAK,IAAE,IAAI,CAAC,KAAK,CAAQ,CAAA;IAC9C,CAAC;SAAM,CAAC;QACN,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAA;QAE1E,OAAO,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,YAAY,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAChG,oBAAC,YAAY,IAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAE,GAAI,CAC3C,CAAC,CAAC,CAAC,CACF,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,IACxB,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE;YACtC,IAAI,KAAK,CAAC,CAAC,CAAE,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBACnC,OAAO,oBAAC,YAAY,IAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,GAAI,CAAA;YACzD,CAAC;iBAAM,CAAC;gBACN,OAAO,oBAAC,IAAI,IAAC,GAAG,EAAE,UAAU,KAAO,KAAK,CAAC,CAAC,CAAE,CAAC,KAAmB,CAAC,IAAI,GAAI,CAAA;YAC3E,CAAC;QACH,CAAC,CAAC,CACE,CACP,CAAA;IACH,CAAC;AACH,CAAC,CAAA;AAED,OAAO,EAAC,aAAa,EAAC,CAAA","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 {Subdued} from './Subdued.js'\nimport {LinksContext} from '../contexts/LinksContext.js'\nimport React, {FunctionComponent, useContext} from 'react'\nimport {Box, Text} from 'ink'\n\nimport type {ListToken, Token, TokenItem} from './token-item.js'\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\nconst InlineBlocks: React.FC<{blocks: Block[]}> = ({blocks}) => {\n return (\n <Text>\n {blocks.map((block, blockIndex) => (\n <Text key={blockIndex}>\n {blockIndex !== 0 && !(typeof block.value !== 'string' && 'char' in block.value) && <Text> </Text>}\n <TokenizedText item={block.value} />\n </Text>\n ))}\n </Text>\n )\n}\n\ninterface TokenizedTextProps {\n item: TokenItem\n}\n\n// Matches CommonMark inline links of the form `[label](url)` and autolinks of\n// the form `<url>`. We deliberately require an explicit `http://` or\n// `https://` scheme on the URL so callers can't accidentally trigger\n// linkification by typing square brackets or angle brackets in plain prose.\n//\n// The URL portion forbids whitespace, the closing delimiter (`)` or `>`), and\n// `<` to keep parsing predictable. URLs that legitimately contain those\n// characters (e.g. balanced parens) must be percent-encoded by the caller —\n// per CommonMark §6.3 / §6.4.\nconst MARKDOWN_LINK_REGEX = /\\[([^[\\]]+)\\]\\((https?:\\/\\/[^()<>\\s]+)\\)|<(https?:\\/\\/[^<>\\s]+)>/g\n\n/**\n * Parses an opt-in CommonMark link or autolink from a plain string token and\n * routes the result through the existing `<Link>` component.\n *\n * Why opt-in rather than auto-detection: server-returned error strings can\n * legitimately contain URL-shaped substrings that are not meant to be\n * clickable (e.g. a tunnel-URL validation error echoing back the user's bad\n * input). Requiring the explicit `[label](url)` / `<url>` shape lets the\n * source of the message (server or client) declare intent, and keeps prose\n * with bare URLs untouched.\n *\n * Only invoked when a `LinksContext` is present (i.e. inside a Banner /\n * Alert / FatalError); outside of that, the underlying `<Link>` would render\n * the URL inline and we'd defeat the wrap-resistance the footnote mechanism\n * provides.\n */\nfunction renderStringWithMarkdownLinks(str: string): JSX.Element {\n const matches = Array.from(str.matchAll(MARKDOWN_LINK_REGEX))\n if (matches.length === 0) {\n return <Text>{str}</Text>\n }\n\n const parts: JSX.Element[] = []\n let cursor = 0\n matches.forEach((match, index) => {\n const start = match.index\n if (start === undefined) {\n return\n }\n const end = start + match[0].length\n if (start > cursor) {\n parts.push(<Text key={`t${index}`}>{str.slice(cursor, start)}</Text>)\n }\n // `[label](url)` captures label in group 1 and url in group 2;\n // `<url>` autolinks capture only the url in group 3.\n const label = match[1]\n const url = match[2] ?? match[3]\n if (url === undefined) {\n return\n }\n parts.push(<Link key={`l${index}`} label={label} url={url} />)\n cursor = end\n })\n if (cursor < str.length) {\n parts.push(<Text key=\"tail\">{str.slice(cursor)}</Text>)\n }\n return <Text>{parts}</Text>\n}\n\n/**\n * `TokenizedText` renders a text string with tokens that can be either strings,\n * links, and commands.\n */\nconst TokenizedText: FunctionComponent<TokenizedTextProps> = ({item}) => {\n const linksContext = useContext(LinksContext)\n if (typeof item === 'string') {\n return linksContext === null ? <Text>{item}</Text> : renderStringWithMarkdownLinks(item)\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 ('subdued' in item) {\n return <Subdued subdued={item.subdued} />\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 if ('bold' in item) {\n return <Text bold>{item.bold}</Text>\n } else if ('info' in item) {\n return <Text color=\"blue\">{item.info}</Text>\n } else if ('warn' in item) {\n return <Text color=\"yellow\">{item.warn}</Text>\n } else if ('error' in item) {\n return <Text color=\"red\">{item.error}</Text>\n } else {\n const groupedItems = item.map(tokenToBlock).reduce(splitByDisplayType, [])\n\n return groupedItems.length === 1 && groupedItems[0]!.every((item) => item.display === 'inline') ? (\n <InlineBlocks blocks={groupedItems[0]!} />\n ) : (\n <Box flexDirection=\"column\">\n {groupedItems.map((items, groupIndex) => {\n if (items[0]!.display === 'inline') {\n return <InlineBlocks blocks={items} key={groupIndex} />\n } else {\n return <List key={groupIndex} {...(items[0]!.value as ListToken).list} />\n }\n })}\n </Box>\n )\n }\n}\n\nexport {TokenizedText}\n"]}
@@ -1,4 +1,5 @@
1
- import { tokenItemToString, TokenizedText } from './TokenizedText.js';
1
+ import { TokenizedText } from './TokenizedText.js';
2
+ import { tokenItemToString } from './token-item.js';
2
3
  import { LinksContext } from '../contexts/LinksContext.js';
3
4
  import { unstyled } from '../../../../public/node/output.js';
4
5
  import { render } from '../../testing/ui.js';
@@ -1 +1 @@
1
- {"version":3,"file":"TokenizedText.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TokenizedText.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {tokenItemToString, TokenizedText} from './TokenizedText.js'\nimport {LinksContext, Link} from '../contexts/LinksContext.js'\nimport {unstyled} from '../../../../public/node/output.js'\nimport {render} from '../../testing/ui.js'\nimport {describe, expect, test, vi} from 'vitest'\nimport supportsHyperlinks from 'supports-hyperlinks'\n\nimport React, {FunctionComponent, useRef} from 'react'\n\nvi.mock('supports-hyperlinks')\n\n// Matches the on-the-wire OSC 8 sequence emitted by `ansiEscapes.link`,\n// which is what `<Link>` ultimately renders when the terminal supports\n// hyperlinks. Format: `ESC ] 8 ; ; URL BEL TEXT ESC ] 8 ; ; BEL`.\nfunction asOsc8Link(url: string, label?: string) {\n return `\\u001b]8;;${url}\\u0007${label ?? url}\\u001b]8;;\\u0007`\n}\n\n// Mirrors the LinksContext that <Banner> sets up at runtime, without pulling\n// the whole Banner border into these tests.\nconst WithLinksContext: FunctionComponent<{children: React.ReactNode}> = ({children}) => {\n const links = useRef<Record<string, Link>>({})\n return (\n <LinksContext.Provider\n value={{\n links,\n addLink: (label, url) => {\n const newId = (Object.keys(links.current).length + 1).toString()\n links.current = {...links.current, [newId]: {label, url}}\n return newId\n },\n }}\n >\n {children}\n </LinksContext.Provider>\n )\n}\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 subdued: '(my-text)',\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 info: 'some info',\n },\n {\n warn: 'some warn',\n },\n {\n error: 'some error',\n },\n ]\n\n const {lastFrame} = render(<TokenizedText item={item} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"Run \\`cd verification-app\\` Example ( https://example.com )! my-app (my-text)\n • Item 1\n • Item 2\n • Item 3\n src/this/is/a/test.js some info some warn some error\"\n `)\n })\n\n describe('markdown-link parsing in plain strings', async () => {\n test('renders strings without a markdown link unchanged', async () => {\n vi.mocked(supportsHyperlinks).stdout = false\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item=\"no link here, just text\" />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toBe('no link here, just text')\n })\n\n test('does not linkify a bare URL — callers must opt in via `[label](url)` or `<url>`', async () => {\n vi.mocked(supportsHyperlinks).stdout = true\n const url = 'https://example.com/docs'\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item={`visit ${url} now`} />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toBe(`visit ${url} now`)\n expect(lastFrame()).not.toContain(']8;;')\n })\n\n test('replaces an opt-in `[label](url)` with the label and a `[N]` footnote anchor when the terminal does not support hyperlinks', async () => {\n vi.mocked(supportsHyperlinks).stdout = false\n const url = 'https://shopify.dev/docs/apps/build/sales-channels/channel-config-extension#specification-properties'\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item={`Reference: [See specification requirements](${url})`} />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toBe('Reference: See specification requirements [1]')\n expect(lastFrame()).not.toContain(url)\n })\n\n test('wraps the label of a `[label](url)` in OSC 8 escapes when the terminal supports hyperlinks', async () => {\n vi.mocked(supportsHyperlinks).stdout = true\n const url = 'https://example.com/docs'\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item={`Reference: [docs page](${url})`} />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toContain(asOsc8Link(url, 'docs page'))\n })\n\n test('renders a label-less `<url>` autolink as a `[N]` anchor and registers the URL in the footnote table', async () => {\n vi.mocked(supportsHyperlinks).stdout = false\n const url = 'https://shopify.dev/docs'\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item={`See specification requirements: <${url}>`} />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toBe('See specification requirements: [1]')\n expect(lastFrame()).not.toContain(url)\n })\n\n test('parses multiple opt-in links in the same string', async () => {\n vi.mocked(supportsHyperlinks).stdout = false\n const first = 'https://example.com/a'\n const second = 'https://example.com/b'\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item={`see [a](${first}) and <${second}>`} />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toBe('see a [1] and [2]')\n })\n\n test('parses back-to-back opt-in links separated only by whitespace', async () => {\n vi.mocked(supportsHyperlinks).stdout = false\n const first = 'https://example.com/a'\n const second = 'https://example.com/b'\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item={`<${first}> <${second}>`} />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toBe('[1] [2]')\n })\n\n test('does not parse markdown links that omit the http(s) scheme', async () => {\n vi.mocked(supportsHyperlinks).stdout = true\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item=\"see [the section](#anchor) for more\" />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toBe('see [the section](#anchor) for more')\n expect(lastFrame()).not.toContain(']8;;')\n })\n\n test('does not parse opt-in markdown when no LinksContext is present (e.g. outside a Banner)', async () => {\n vi.mocked(supportsHyperlinks).stdout = true\n const url = 'https://example.com/docs'\n\n const {lastFrame} = render(<TokenizedText item={`see [docs](${url}) now`} />)\n\n expect(lastFrame()).toBe(`see [docs](${url}) now`)\n expect(lastFrame()).not.toContain(']8;;')\n })\n\n test('echoing back a user-supplied URL inside an error message is left as plain text', async () => {\n // Regression: an earlier auto-detection approach would turn the\n // user's bad `--tunnel-url` value into a clickable OSC-8 link,\n // which is misleading. With opt-in markdown the bare URL stays\n // as-is and only the doc reference — which the server marks up —\n // becomes clickable.\n vi.mocked(supportsHyperlinks).stdout = true\n const tunnelUrl = 'https://wrong'\n const docUrl = 'https://shopify.dev/docs/tunnels'\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item={`Invalid tunnel URL: ${tunnelUrl}. See [tunnel docs](${docUrl}).`} />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toContain(`Invalid tunnel URL: ${tunnelUrl}.`)\n expect(lastFrame()).toContain(asOsc8Link(docUrl, 'tunnel docs'))\n // The user-supplied URL must not be wrapped in an OSC 8 escape.\n expect(lastFrame()).not.toContain(`\\u001b]8;;${tunnelUrl}`)\n })\n })\n\n describe('tokenItemToString', async () => {\n test(\"doesn't add a space before char\", async () => {\n expect(tokenItemToString(['Run', {char: '!'}])).toBe('Run!')\n })\n\n test('it concatenates list items inline', async () => {\n expect(\n tokenItemToString([\n 'Run',\n {\n list: {\n items: ['Item 1', 'Item 2', 'Item 3'],\n },\n },\n ]),\n ).toBe('Run Item 1 Item 2 Item 3')\n })\n })\n})\n"]}
1
+ {"version":3,"file":"TokenizedText.test.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/TokenizedText.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import {TokenizedText} from './TokenizedText.js'\nimport {tokenItemToString} from './token-item.js'\nimport {LinksContext, Link} from '../contexts/LinksContext.js'\nimport {unstyled} from '../../../../public/node/output.js'\nimport {render} from '../../testing/ui.js'\nimport {describe, expect, test, vi} from 'vitest'\nimport supportsHyperlinks from 'supports-hyperlinks'\n\nimport React, {FunctionComponent, useRef} from 'react'\n\nvi.mock('supports-hyperlinks')\n\n// Matches the on-the-wire OSC 8 sequence emitted by `ansiEscapes.link`,\n// which is what `<Link>` ultimately renders when the terminal supports\n// hyperlinks. Format: `ESC ] 8 ; ; URL BEL TEXT ESC ] 8 ; ; BEL`.\nfunction asOsc8Link(url: string, label?: string) {\n return `\\u001b]8;;${url}\\u0007${label ?? url}\\u001b]8;;\\u0007`\n}\n\n// Mirrors the LinksContext that <Banner> sets up at runtime, without pulling\n// the whole Banner border into these tests.\nconst WithLinksContext: FunctionComponent<{children: React.ReactNode}> = ({children}) => {\n const links = useRef<Record<string, Link>>({})\n return (\n <LinksContext.Provider\n value={{\n links,\n addLink: (label, url) => {\n const newId = (Object.keys(links.current).length + 1).toString()\n links.current = {...links.current, [newId]: {label, url}}\n return newId\n },\n }}\n >\n {children}\n </LinksContext.Provider>\n )\n}\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 subdued: '(my-text)',\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 info: 'some info',\n },\n {\n warn: 'some warn',\n },\n {\n error: 'some error',\n },\n ]\n\n const {lastFrame} = render(<TokenizedText item={item} />)\n\n expect(unstyled(lastFrame()!)).toMatchInlineSnapshot(`\n \"Run \\`cd verification-app\\` Example ( https://example.com )! my-app (my-text)\n • Item 1\n • Item 2\n • Item 3\n src/this/is/a/test.js some info some warn some error\"\n `)\n })\n\n describe('markdown-link parsing in plain strings', async () => {\n test('renders strings without a markdown link unchanged', async () => {\n vi.mocked(supportsHyperlinks).stdout = false\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item=\"no link here, just text\" />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toBe('no link here, just text')\n })\n\n test('does not linkify a bare URL — callers must opt in via `[label](url)` or `<url>`', async () => {\n vi.mocked(supportsHyperlinks).stdout = true\n const url = 'https://example.com/docs'\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item={`visit ${url} now`} />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toBe(`visit ${url} now`)\n expect(lastFrame()).not.toContain(']8;;')\n })\n\n test('replaces an opt-in `[label](url)` with the label and a `[N]` footnote anchor when the terminal does not support hyperlinks', async () => {\n vi.mocked(supportsHyperlinks).stdout = false\n const url = 'https://shopify.dev/docs/apps/build/sales-channels/channel-config-extension#specification-properties'\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item={`Reference: [See specification requirements](${url})`} />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toBe('Reference: See specification requirements [1]')\n expect(lastFrame()).not.toContain(url)\n })\n\n test('wraps the label of a `[label](url)` in OSC 8 escapes when the terminal supports hyperlinks', async () => {\n vi.mocked(supportsHyperlinks).stdout = true\n const url = 'https://example.com/docs'\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item={`Reference: [docs page](${url})`} />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toContain(asOsc8Link(url, 'docs page'))\n })\n\n test('renders a label-less `<url>` autolink as a `[N]` anchor and registers the URL in the footnote table', async () => {\n vi.mocked(supportsHyperlinks).stdout = false\n const url = 'https://shopify.dev/docs'\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item={`See specification requirements: <${url}>`} />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toBe('See specification requirements: [1]')\n expect(lastFrame()).not.toContain(url)\n })\n\n test('parses multiple opt-in links in the same string', async () => {\n vi.mocked(supportsHyperlinks).stdout = false\n const first = 'https://example.com/a'\n const second = 'https://example.com/b'\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item={`see [a](${first}) and <${second}>`} />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toBe('see a [1] and [2]')\n })\n\n test('parses back-to-back opt-in links separated only by whitespace', async () => {\n vi.mocked(supportsHyperlinks).stdout = false\n const first = 'https://example.com/a'\n const second = 'https://example.com/b'\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item={`<${first}> <${second}>`} />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toBe('[1] [2]')\n })\n\n test('does not parse markdown links that omit the http(s) scheme', async () => {\n vi.mocked(supportsHyperlinks).stdout = true\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item=\"see [the section](#anchor) for more\" />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toBe('see [the section](#anchor) for more')\n expect(lastFrame()).not.toContain(']8;;')\n })\n\n test('does not parse opt-in markdown when no LinksContext is present (e.g. outside a Banner)', async () => {\n vi.mocked(supportsHyperlinks).stdout = true\n const url = 'https://example.com/docs'\n\n const {lastFrame} = render(<TokenizedText item={`see [docs](${url}) now`} />)\n\n expect(lastFrame()).toBe(`see [docs](${url}) now`)\n expect(lastFrame()).not.toContain(']8;;')\n })\n\n test('echoing back a user-supplied URL inside an error message is left as plain text', async () => {\n // Regression: an earlier auto-detection approach would turn the\n // user's bad `--tunnel-url` value into a clickable OSC-8 link,\n // which is misleading. With opt-in markdown the bare URL stays\n // as-is and only the doc reference — which the server marks up —\n // becomes clickable.\n vi.mocked(supportsHyperlinks).stdout = true\n const tunnelUrl = 'https://wrong'\n const docUrl = 'https://shopify.dev/docs/tunnels'\n\n const {lastFrame} = render(\n <WithLinksContext>\n <TokenizedText item={`Invalid tunnel URL: ${tunnelUrl}. See [tunnel docs](${docUrl}).`} />\n </WithLinksContext>,\n )\n\n expect(lastFrame()).toContain(`Invalid tunnel URL: ${tunnelUrl}.`)\n expect(lastFrame()).toContain(asOsc8Link(docUrl, 'tunnel docs'))\n // The user-supplied URL must not be wrapped in an OSC 8 escape.\n expect(lastFrame()).not.toContain(`\\u001b]8;;${tunnelUrl}`)\n })\n })\n\n describe('tokenItemToString', async () => {\n test(\"doesn't add a space before char\", async () => {\n expect(tokenItemToString(['Run', {char: '!'}])).toBe('Run!')\n })\n\n test('it concatenates list items inline', async () => {\n expect(\n tokenItemToString([\n 'Run',\n {\n list: {\n items: ['Item 1', 'Item 2', 'Item 3'],\n },\n },\n ]),\n ).toBe('Run Item 1 Item 2 Item 3')\n })\n })\n})\n"]}
@@ -0,0 +1,38 @@
1
+ export interface LinkToken {
2
+ link: {
3
+ label?: string;
4
+ url: string;
5
+ };
6
+ }
7
+ export interface UserInputToken {
8
+ userInput: string;
9
+ }
10
+ export interface ListToken {
11
+ list: {
12
+ title?: TokenItem<InlineToken>;
13
+ items: TokenItem<InlineToken>[];
14
+ ordered?: boolean;
15
+ };
16
+ }
17
+ export interface BoldToken {
18
+ bold: string;
19
+ }
20
+ export type Token = string | {
21
+ command: string;
22
+ } | LinkToken | {
23
+ char: string;
24
+ } | UserInputToken | {
25
+ subdued: string;
26
+ } | {
27
+ filePath: string;
28
+ } | ListToken | BoldToken | {
29
+ info: string;
30
+ } | {
31
+ warn: string;
32
+ } | {
33
+ error: string;
34
+ };
35
+ export type InlineToken = Exclude<Token, ListToken>;
36
+ export type TokenItem<T extends Token = Token> = T | T[];
37
+ export declare function tokenItemToString(token: TokenItem): string;
38
+ export declare function appendToTokenItem(token: TokenItem, suffix: string): TokenItem;
@@ -0,0 +1,63 @@
1
+ // Token shapes and the pure helpers that operate on them.
2
+ //
3
+ // These live apart from `TokenizedText.tsx` on purpose. That file is a React
4
+ // component module: importing it pulls in `react` and `ink`, and through Ink,
5
+ // `react-reconciler`, `yoga-layout` and its WebAssembly. Non-rendering modules
6
+ // such as `output.ts`, `error.ts` and `common/string.ts` need only the types
7
+ // and `tokenItemToString`, and importing them from here keeps the terminal UI
8
+ // runtime out of the startup path of every command.
9
+ export function tokenItemToString(token) {
10
+ if (typeof token === 'string') {
11
+ return token;
12
+ }
13
+ else if ('command' in token) {
14
+ return token.command;
15
+ }
16
+ else if ('link' in token) {
17
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- empty label should fall through to url
18
+ return token.link.label || token.link.url;
19
+ }
20
+ else if ('char' in token) {
21
+ return token.char;
22
+ }
23
+ else if ('userInput' in token) {
24
+ return token.userInput;
25
+ }
26
+ else if ('subdued' in token) {
27
+ return token.subdued;
28
+ }
29
+ else if ('filePath' in token) {
30
+ return token.filePath;
31
+ }
32
+ else if ('list' in token) {
33
+ return token.list.items.map(tokenItemToString).join(' ');
34
+ }
35
+ else if ('bold' in token) {
36
+ return token.bold;
37
+ }
38
+ else if ('info' in token) {
39
+ return token.info;
40
+ }
41
+ else if ('warn' in token) {
42
+ return token.warn;
43
+ }
44
+ else if ('error' in token) {
45
+ return token.error;
46
+ }
47
+ else {
48
+ return token
49
+ .map((item, index) => {
50
+ if (index !== 0 && !(typeof item !== 'string' && 'char' in item)) {
51
+ return ` ${tokenItemToString(item)}`;
52
+ }
53
+ else {
54
+ return tokenItemToString(item);
55
+ }
56
+ })
57
+ .join('');
58
+ }
59
+ }
60
+ export function appendToTokenItem(token, suffix) {
61
+ return Array.isArray(token) ? [...token, { char: suffix }] : [token, { char: suffix }];
62
+ }
63
+ //# sourceMappingURL=token-item.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-item.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/components/token-item.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,+EAA+E;AAC/E,6EAA6E;AAC7E,8EAA8E;AAC9E,oDAAoD;AAwDpD,MAAM,UAAU,iBAAiB,CAAC,KAAgB;IAChD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAA;IACd,CAAC;SAAM,IAAI,SAAS,IAAI,KAAK,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC,OAAO,CAAA;IACtB,CAAC;SAAM,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;QAC3B,kHAAkH;QAClH,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAA;IAC3C,CAAC;SAAM,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,IAAI,CAAA;IACnB,CAAC;SAAM,IAAI,WAAW,IAAI,KAAK,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC,SAAS,CAAA;IACxB,CAAC;SAAM,IAAI,SAAS,IAAI,KAAK,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC,OAAO,CAAA;IACtB,CAAC;SAAM,IAAI,UAAU,IAAI,KAAK,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC,QAAQ,CAAA;IACvB,CAAC;SAAM,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC1D,CAAC;SAAM,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,IAAI,CAAA;IACnB,CAAC;SAAM,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,IAAI,CAAA;IACnB,CAAC;SAAM,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,IAAI,CAAA;IACnB,CAAC;SAAM,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC,KAAK,CAAA;IACpB,CAAC;SAAM,CAAC;QACN,OAAO,KAAK;aACT,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YACnB,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,MAAM,IAAI,IAAI,CAAC,EAAE,CAAC;gBACjE,OAAO,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAA;YACtC,CAAC;iBAAM,CAAC;gBACN,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAA;YAChC,CAAC;QACH,CAAC,CAAC;aACD,IAAI,CAAC,EAAE,CAAC,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAgB,EAAE,MAAc;IAChE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,EAAC,IAAI,EAAE,MAAM,EAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,EAAC,IAAI,EAAE,MAAM,EAAC,CAAC,CAAA;AACpF,CAAC","sourcesContent":["// Token shapes and the pure helpers that operate on them.\n//\n// These live apart from `TokenizedText.tsx` on purpose. That file is a React\n// component module: importing it pulls in `react` and `ink`, and through Ink,\n// `react-reconciler`, `yoga-layout` and its WebAssembly. Non-rendering modules\n// such as `output.ts`, `error.ts` and `common/string.ts` need only the types\n// and `tokenItemToString`, and importing them from here keeps the terminal UI\n// runtime out of the startup path of every command.\n\nexport interface LinkToken {\n link: {\n label?: string\n url: string\n }\n}\n\nexport interface UserInputToken {\n userInput: string\n}\n\nexport interface ListToken {\n list: {\n title?: TokenItem<InlineToken>\n items: TokenItem<InlineToken>[]\n ordered?: boolean\n }\n}\n\nexport interface BoldToken {\n bold: string\n}\n\nexport type Token =\n | string\n | {\n command: string\n }\n | LinkToken\n | {\n char: string\n }\n | UserInputToken\n | {\n subdued: string\n }\n | {\n filePath: string\n }\n | ListToken\n | BoldToken\n | {\n info: string\n }\n | {\n warn: string\n }\n | {\n error: string\n }\n\nexport type InlineToken = Exclude<Token, ListToken>\nexport type TokenItem<T extends Token = Token> = T | T[]\n\nexport function tokenItemToString(token: TokenItem): string {\n if (typeof token === 'string') {\n return token\n } else if ('command' in token) {\n return token.command\n } else if ('link' in token) {\n // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- empty label should fall through to url\n return token.link.label || token.link.url\n } else if ('char' in token) {\n return token.char\n } else if ('userInput' in token) {\n return token.userInput\n } else if ('subdued' in token) {\n return token.subdued\n } else if ('filePath' in token) {\n return token.filePath\n } else if ('list' in token) {\n return token.list.items.map(tokenItemToString).join(' ')\n } else if ('bold' in token) {\n return token.bold\n } else if ('info' in token) {\n return token.info\n } else if ('warn' in token) {\n return token.warn\n } else if ('error' in token) {\n return token.error\n } else {\n return token\n .map((item, index) => {\n if (index !== 0 && !(typeof item !== 'string' && 'char' in item)) {\n return ` ${tokenItemToString(item)}`\n } else {\n return tokenItemToString(item)\n }\n })\n .join('')\n }\n}\n\nexport function appendToTokenItem(token: TokenItem, suffix: string): TokenItem {\n return Array.isArray(token) ? [...token, {char: suffix}] : [token, {char: suffix}]\n}\n"]}
@@ -1,21 +1,22 @@
1
1
  import { useComplete } from '../../ui.js';
2
2
  import { useEffect, useLayoutEffect, useState } from 'react';
3
3
  const noop = () => Promise.resolve();
4
+ function getAbortError(abortSignal) {
5
+ return abortSignal?.reason?.name === 'AbortError' ? undefined : abortSignal?.reason;
6
+ }
4
7
  export default function useAbortSignal(abortSignal, onAbort = noop) {
5
8
  const complete = useComplete();
6
9
  const [isAborted, setIsAborted] = useState(false);
7
10
  useLayoutEffect(() => {
8
11
  abortSignal?.addEventListener('abort', () => {
9
- const abortWithError = abortSignal.reason.message === 'AbortError' ? undefined : abortSignal.reason;
10
- onAbort(abortWithError)
12
+ onAbort(getAbortError(abortSignal))
11
13
  .then(() => setIsAborted(true))
12
14
  .catch(() => { });
13
15
  });
14
16
  }, []);
15
17
  useEffect(() => {
16
18
  if (isAborted) {
17
- const abortWithError = abortSignal?.reason?.message === 'AbortError' ? undefined : abortSignal?.reason;
18
- complete(abortWithError);
19
+ complete(getAbortError(abortSignal));
19
20
  }
20
21
  }, [isAborted]);
21
22
  return { isAborted };
@@ -1 +1 @@
1
- {"version":3,"file":"use-abort-signal.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/hooks/use-abort-signal.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;AACvC,OAAO,EAAC,SAAS,EAAE,eAAe,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AAE1D,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAA;AAEpC,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,WAAyB,EAAE,UAA8C,IAAI;IAClH,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAEjD,eAAe,CAAC,GAAG,EAAE;QACnB,WAAW,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YAC1C,MAAM,cAAc,GAAG,WAAW,CAAC,MAAM,CAAC,OAAO,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAA;YACnG,OAAO,CAAC,cAAc,CAAC;iBACpB,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;iBAC9B,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACpB,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,cAAc,GAAG,WAAW,EAAE,MAAM,EAAE,OAAO,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE,MAAM,CAAA;YACtG,QAAQ,CAAC,cAAc,CAAC,CAAA;QAC1B,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAA;IAEf,OAAO,EAAC,SAAS,EAAC,CAAA;AACpB,CAAC","sourcesContent":["import {AbortSignal} from '../../../../public/node/abort.js'\nimport {useComplete} from '../../ui.js'\nimport {useEffect, useLayoutEffect, useState} from 'react'\n\nconst noop = () => Promise.resolve()\n\nexport default function useAbortSignal(abortSignal?: AbortSignal, onAbort: (error?: unknown) => Promise<void> = noop) {\n const complete = useComplete()\n const [isAborted, setIsAborted] = useState(false)\n\n useLayoutEffect(() => {\n abortSignal?.addEventListener('abort', () => {\n const abortWithError = abortSignal.reason.message === 'AbortError' ? undefined : abortSignal.reason\n onAbort(abortWithError)\n .then(() => setIsAborted(true))\n .catch(() => {})\n })\n }, [])\n\n useEffect(() => {\n if (isAborted) {\n const abortWithError = abortSignal?.reason?.message === 'AbortError' ? undefined : abortSignal?.reason\n complete(abortWithError)\n }\n }, [isAborted])\n\n return {isAborted}\n}\n"]}
1
+ {"version":3,"file":"use-abort-signal.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/hooks/use-abort-signal.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,WAAW,EAAC,MAAM,aAAa,CAAA;AACvC,OAAO,EAAC,SAAS,EAAE,eAAe,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AAE1D,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAA;AAEpC,SAAS,aAAa,CAAC,WAAyB;IAC9C,OAAO,WAAW,EAAE,MAAM,EAAE,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE,MAAM,CAAA;AACrF,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,WAAyB,EAAE,UAA8C,IAAI;IAClH,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAEjD,eAAe,CAAC,GAAG,EAAE;QACnB,WAAW,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YAC1C,OAAO,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;iBAChC,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;iBAC9B,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACpB,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,EAAE,CAAC;YACd,QAAQ,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAA;QACtC,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAA;IAEf,OAAO,EAAC,SAAS,EAAC,CAAA;AACpB,CAAC","sourcesContent":["import {AbortSignal} from '../../../../public/node/abort.js'\nimport {useComplete} from '../../ui.js'\nimport {useEffect, useLayoutEffect, useState} from 'react'\n\nconst noop = () => Promise.resolve()\n\nfunction getAbortError(abortSignal?: AbortSignal) {\n return abortSignal?.reason?.name === 'AbortError' ? undefined : abortSignal?.reason\n}\n\nexport default function useAbortSignal(abortSignal?: AbortSignal, onAbort: (error?: unknown) => Promise<void> = noop) {\n const complete = useComplete()\n const [isAborted, setIsAborted] = useState(false)\n\n useLayoutEffect(() => {\n abortSignal?.addEventListener('abort', () => {\n onAbort(getAbortError(abortSignal))\n .then(() => setIsAborted(true))\n .catch(() => {})\n })\n }, [])\n\n useEffect(() => {\n if (isAborted) {\n complete(getAbortError(abortSignal))\n }\n }, [isAborted])\n\n return {isAborted}\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  import { useReducer, useCallback, useMemo, useState } from 'react';
2
2
  import { isDeepStrictEqual } from 'node:util';
3
3
  export default class OptionMap extends Map {
4
+ first;
4
5
  constructor(options) {
5
6
  const items = [];
6
7
  let firstItem;
@@ -16,7 +17,7 @@ export default class OptionMap extends Map {
16
17
  if (previous) {
17
18
  previous.next = item;
18
19
  }
19
- firstItem ?? (firstItem = item);
20
+ firstItem ??= item;
20
21
  items.push([option.value, item]);
21
22
  index++;
22
23
  previous = item;
@@ -1 +1 @@
1
- {"version":3,"file":"use-select-state.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/hooks/use-select-state.ts"],"names":[],"mappings":"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","sourcesContent":["import {Item} from '../components/SelectInput.js'\nimport {useReducer, useCallback, useMemo, useState} from 'react'\nimport {isDeepStrictEqual} from 'node:util'\n\ntype Option<T> = Item<T>\n\ntype OptionMapItem<T> = Option<T> & {\n previous: OptionMapItem<T> | undefined\n next: OptionMapItem<T> | undefined\n index: number\n}\n\nexport default class OptionMap<T> extends Map<T, OptionMapItem<T>> {\n readonly first: OptionMapItem<T> | undefined\n\n constructor(options: Option<T>[]) {\n const items: [T, OptionMapItem<T>][] = []\n let firstItem: OptionMapItem<T> | undefined\n let previous: OptionMapItem<T> | undefined\n let index = 0\n\n for (const option of options) {\n const item = {\n ...option,\n previous,\n next: undefined,\n index,\n }\n\n if (previous) {\n previous.next = item\n }\n\n firstItem ??= item\n\n items.push([option.value, item])\n index++\n previous = item\n }\n\n super(items)\n this.first = firstItem\n }\n}\n\ninterface State<T> {\n /**\n * Map where key is option's value and value is option's index.\n */\n optionMap: OptionMap<T>\n\n /**\n * Number of visible options.\n */\n visibleOptionCount: number\n\n /**\n * Index of the first visible option.\n */\n visibleFromIndex: number\n\n /**\n * Index of the last visible option.\n */\n visibleToIndex: number\n\n /**\n * Value of the previously selected option.\n */\n previousValue: T | undefined\n\n /**\n * Value of the selected option.\n */\n value: T | undefined\n}\n\ntype Action<T> = SelectNextOptionAction | SelectPreviousOptionAction | SelectOptionAction<T> | ResetAction<T>\n\ninterface SelectNextOptionAction {\n type: 'select-next-option'\n}\n\ninterface SelectPreviousOptionAction {\n type: 'select-previous-option'\n}\n\ninterface SelectOptionAction<T> {\n type: 'select-option'\n option: Option<T>\n}\n\ninterface ResetAction<T> {\n type: 'reset'\n state: State<T>\n}\n\nconst reducer = <T>(state: State<T>, action: Action<T>): State<T> => {\n switch (action.type) {\n case 'select-next-option': {\n if (typeof state.value === 'undefined') {\n return state\n }\n\n const item = state.optionMap.get(state.value)\n\n if (!item) {\n return state\n }\n\n let next = item.next\n\n while (next && next.disabled) {\n next = next.next\n }\n\n if (!next) {\n return state\n }\n\n const needsToScroll = next.index > state.visibleToIndex\n\n if (!needsToScroll) {\n return {\n ...state,\n value: next.value,\n }\n }\n\n const nextVisibleToIndex = next.index\n const nextVisibleFromIndex = nextVisibleToIndex - state.visibleOptionCount + 1\n\n return {\n ...state,\n value: next.value,\n visibleFromIndex: nextVisibleFromIndex,\n visibleToIndex: nextVisibleToIndex,\n previousValue: state.value,\n }\n }\n\n case 'select-previous-option': {\n if (typeof state.value === 'undefined') {\n return state\n }\n\n const item = state.optionMap.get(state.value)\n\n if (!item) {\n return state\n }\n\n let previous = item.previous\n\n while (previous && previous.disabled) {\n previous = previous.previous\n }\n\n if (!previous) {\n return state\n }\n\n const needsToScroll = previous.index < state.visibleFromIndex\n\n if (!needsToScroll) {\n return {\n ...state,\n value: previous.value,\n }\n }\n\n const nextVisibleFromIndex = previous.index\n const nextVisibleToIndex = nextVisibleFromIndex + state.visibleOptionCount - 1\n\n return {\n ...state,\n value: previous.value,\n visibleFromIndex: nextVisibleFromIndex,\n visibleToIndex: nextVisibleToIndex,\n previousValue: state.value,\n }\n }\n\n case 'select-option': {\n const item = state.optionMap.get(action.option.value)\n\n if (!item) {\n return state\n }\n\n return {\n ...state,\n value: item.value,\n previousValue: state.value,\n }\n }\n\n case 'reset': {\n return action.state\n }\n\n default: {\n return state\n }\n }\n}\n\nexport interface UseSelectStateProps<T> {\n /**\n * Number of items to display.\n *\n */\n visibleOptionCount: number\n\n /**\n * Options.\n */\n options: Option<T>[]\n\n /**\n * Initially selected option's value.\n */\n defaultValue?: T\n}\n\nexport type SelectState<T> = Pick<State<T>, 'visibleOptionCount' | 'visibleFromIndex' | 'visibleToIndex' | 'value'> & {\n /**\n * Visible options.\n */\n visibleOptions: (Option<T> & {index: number})[]\n\n /**\n * Select next option and scroll the list down, if needed.\n */\n selectNextOption: () => void\n\n /**\n * Select previous option and scroll the list up, if needed.\n */\n selectPreviousOption: () => void\n\n /**\n * Select option directly.\n */\n selectOption: (option: Option<T>) => void\n}\n\ntype CreateDefaultStateProps<T> = Pick<UseSelectStateProps<T>, 'visibleOptionCount' | 'defaultValue' | 'options'>\n\nconst createDefaultState = <T>({\n visibleOptionCount: customVisibleOptionCount,\n defaultValue,\n options,\n}: CreateDefaultStateProps<T>) => {\n const visibleOptionCount =\n typeof customVisibleOptionCount === 'number' ? Math.min(customVisibleOptionCount, options.length) : options.length\n const optionMap = new OptionMap(options)\n const defaultOption = typeof defaultValue === 'undefined' ? undefined : optionMap.get(defaultValue)\n let option = defaultOption && !defaultOption.disabled ? defaultOption : optionMap.first\n\n while (option && option.disabled) {\n option = option.next\n }\n\n return {\n optionMap,\n visibleOptionCount,\n visibleFromIndex: 0,\n visibleToIndex: visibleOptionCount - 1,\n value: option?.value,\n previousValue: option?.value,\n }\n}\n\nexport const useSelectState = <T>({visibleOptionCount, options, defaultValue}: UseSelectStateProps<T>) => {\n const [state, dispatch] = useReducer(reducer, {visibleOptionCount, defaultValue, options}, createDefaultState)\n const [lastOptions, setLastOptions] = useState(options)\n const [lastVisibleOptionCount, setLastVisibleOptionCount] = useState(visibleOptionCount)\n\n if (options !== lastOptions && !isDeepStrictEqual(options, lastOptions)) {\n dispatch({\n type: 'reset',\n state: createDefaultState({visibleOptionCount, defaultValue, options}),\n })\n\n setLastOptions(options)\n }\n\n if (visibleOptionCount !== lastVisibleOptionCount) {\n dispatch({\n type: 'reset',\n state: createDefaultState({visibleOptionCount, defaultValue, options}),\n })\n\n setLastVisibleOptionCount(visibleOptionCount)\n }\n\n const selectNextOption = useCallback(() => {\n dispatch({\n type: 'select-next-option',\n })\n }, [])\n\n const selectPreviousOption = useCallback(() => {\n dispatch({\n type: 'select-previous-option',\n })\n }, [])\n\n const selectOption = useCallback(({option}: {option: Option<T>}) => {\n dispatch({\n type: 'select-option',\n option,\n })\n }, [])\n\n const visibleOptions = useMemo(() => {\n return options.slice(state.visibleFromIndex)\n }, [options, state.visibleFromIndex])\n\n return {\n visibleFromIndex: state.visibleFromIndex,\n visibleToIndex: state.visibleToIndex,\n value: state.value,\n visibleOptions,\n selectNextOption,\n selectPreviousOption,\n selectOption,\n previousValue: state.previousValue,\n }\n}\n"]}
1
+ {"version":3,"file":"use-select-state.js","sourceRoot":"","sources":["../../../../../src/private/node/ui/hooks/use-select-state.ts"],"names":[],"mappings":"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","sourcesContent":["import {Item} from '../components/SelectInput.js'\nimport {useReducer, useCallback, useMemo, useState} from 'react'\nimport {isDeepStrictEqual} from 'node:util'\n\ntype Option<T> = Item<T>\n\ntype OptionMapItem<T> = Option<T> & {\n previous: OptionMapItem<T> | undefined\n next: OptionMapItem<T> | undefined\n index: number\n}\n\nexport default class OptionMap<T> extends Map<T, OptionMapItem<T>> {\n readonly first: OptionMapItem<T> | undefined\n\n constructor(options: Option<T>[]) {\n const items: [T, OptionMapItem<T>][] = []\n let firstItem: OptionMapItem<T> | undefined\n let previous: OptionMapItem<T> | undefined\n let index = 0\n\n for (const option of options) {\n const item = {\n ...option,\n previous,\n next: undefined,\n index,\n }\n\n if (previous) {\n previous.next = item\n }\n\n firstItem ??= item\n\n items.push([option.value, item])\n index++\n previous = item\n }\n\n super(items)\n this.first = firstItem\n }\n}\n\ninterface State<T> {\n /**\n * Map where key is option's value and value is option's index.\n */\n optionMap: OptionMap<T>\n\n /**\n * Number of visible options.\n */\n visibleOptionCount: number\n\n /**\n * Index of the first visible option.\n */\n visibleFromIndex: number\n\n /**\n * Index of the last visible option.\n */\n visibleToIndex: number\n\n /**\n * Value of the previously selected option.\n */\n previousValue: T | undefined\n\n /**\n * Value of the selected option.\n */\n value: T | undefined\n}\n\ntype Action<T> = SelectNextOptionAction | SelectPreviousOptionAction | SelectOptionAction<T> | ResetAction<T>\n\ninterface SelectNextOptionAction {\n type: 'select-next-option'\n}\n\ninterface SelectPreviousOptionAction {\n type: 'select-previous-option'\n}\n\ninterface SelectOptionAction<T> {\n type: 'select-option'\n option: Option<T>\n}\n\ninterface ResetAction<T> {\n type: 'reset'\n state: State<T>\n}\n\nconst reducer = <T>(state: State<T>, action: Action<T>): State<T> => {\n switch (action.type) {\n case 'select-next-option': {\n if (typeof state.value === 'undefined') {\n return state\n }\n\n const item = state.optionMap.get(state.value)\n\n if (!item) {\n return state\n }\n\n let next = item.next\n\n while (next && next.disabled) {\n next = next.next\n }\n\n if (!next) {\n return state\n }\n\n const needsToScroll = next.index > state.visibleToIndex\n\n if (!needsToScroll) {\n return {\n ...state,\n value: next.value,\n }\n }\n\n const nextVisibleToIndex = next.index\n const nextVisibleFromIndex = nextVisibleToIndex - state.visibleOptionCount + 1\n\n return {\n ...state,\n value: next.value,\n visibleFromIndex: nextVisibleFromIndex,\n visibleToIndex: nextVisibleToIndex,\n previousValue: state.value,\n }\n }\n\n case 'select-previous-option': {\n if (typeof state.value === 'undefined') {\n return state\n }\n\n const item = state.optionMap.get(state.value)\n\n if (!item) {\n return state\n }\n\n let previous = item.previous\n\n while (previous && previous.disabled) {\n previous = previous.previous\n }\n\n if (!previous) {\n return state\n }\n\n const needsToScroll = previous.index < state.visibleFromIndex\n\n if (!needsToScroll) {\n return {\n ...state,\n value: previous.value,\n }\n }\n\n const nextVisibleFromIndex = previous.index\n const nextVisibleToIndex = nextVisibleFromIndex + state.visibleOptionCount - 1\n\n return {\n ...state,\n value: previous.value,\n visibleFromIndex: nextVisibleFromIndex,\n visibleToIndex: nextVisibleToIndex,\n previousValue: state.value,\n }\n }\n\n case 'select-option': {\n const item = state.optionMap.get(action.option.value)\n\n if (!item) {\n return state\n }\n\n return {\n ...state,\n value: item.value,\n previousValue: state.value,\n }\n }\n\n case 'reset': {\n return action.state\n }\n\n default: {\n return state\n }\n }\n}\n\nexport interface UseSelectStateProps<T> {\n /**\n * Number of items to display.\n *\n */\n visibleOptionCount: number\n\n /**\n * Options.\n */\n options: Option<T>[]\n\n /**\n * Initially selected option's value.\n */\n defaultValue?: T\n}\n\nexport type SelectState<T> = Pick<State<T>, 'visibleOptionCount' | 'visibleFromIndex' | 'visibleToIndex' | 'value'> & {\n /**\n * Visible options.\n */\n visibleOptions: (Option<T> & {index: number})[]\n\n /**\n * Select next option and scroll the list down, if needed.\n */\n selectNextOption: () => void\n\n /**\n * Select previous option and scroll the list up, if needed.\n */\n selectPreviousOption: () => void\n\n /**\n * Select option directly.\n */\n selectOption: (option: Option<T>) => void\n}\n\ntype CreateDefaultStateProps<T> = Pick<UseSelectStateProps<T>, 'visibleOptionCount' | 'defaultValue' | 'options'>\n\nconst createDefaultState = <T>({\n visibleOptionCount: customVisibleOptionCount,\n defaultValue,\n options,\n}: CreateDefaultStateProps<T>) => {\n const visibleOptionCount =\n typeof customVisibleOptionCount === 'number' ? Math.min(customVisibleOptionCount, options.length) : options.length\n const optionMap = new OptionMap(options)\n const defaultOption = typeof defaultValue === 'undefined' ? undefined : optionMap.get(defaultValue)\n let option = defaultOption && !defaultOption.disabled ? defaultOption : optionMap.first\n\n while (option && option.disabled) {\n option = option.next\n }\n\n return {\n optionMap,\n visibleOptionCount,\n visibleFromIndex: 0,\n visibleToIndex: visibleOptionCount - 1,\n value: option?.value,\n previousValue: option?.value,\n }\n}\n\nexport const useSelectState = <T>({visibleOptionCount, options, defaultValue}: UseSelectStateProps<T>) => {\n const [state, dispatch] = useReducer(reducer, {visibleOptionCount, defaultValue, options}, createDefaultState)\n const [lastOptions, setLastOptions] = useState(options)\n const [lastVisibleOptionCount, setLastVisibleOptionCount] = useState(visibleOptionCount)\n\n if (options !== lastOptions && !isDeepStrictEqual(options, lastOptions)) {\n dispatch({\n type: 'reset',\n state: createDefaultState({visibleOptionCount, defaultValue, options}),\n })\n\n setLastOptions(options)\n }\n\n if (visibleOptionCount !== lastVisibleOptionCount) {\n dispatch({\n type: 'reset',\n state: createDefaultState({visibleOptionCount, defaultValue, options}),\n })\n\n setLastVisibleOptionCount(visibleOptionCount)\n }\n\n const selectNextOption = useCallback(() => {\n dispatch({\n type: 'select-next-option',\n })\n }, [])\n\n const selectPreviousOption = useCallback(() => {\n dispatch({\n type: 'select-previous-option',\n })\n }, [])\n\n const selectOption = useCallback(({option}: {option: Option<T>}) => {\n dispatch({\n type: 'select-option',\n option,\n })\n }, [])\n\n const visibleOptions = useMemo(() => {\n return options.slice(state.visibleFromIndex)\n }, [options, state.visibleFromIndex])\n\n return {\n visibleFromIndex: state.visibleFromIndex,\n visibleToIndex: state.visibleToIndex,\n value: state.value,\n visibleOptions,\n selectNextOption,\n selectPreviousOption,\n selectOption,\n previousValue: state.previousValue,\n }\n}\n"]}
@@ -1,16 +1,16 @@
1
- import { TokenItem } from './components/TokenizedText.js';
2
- export declare function messageWithPunctuation(message: TokenItem): string | {
1
+ import { type TokenItem } from './components/token-item.js';
2
+ export declare function messageWithPunctuation(message: TokenItem): string | import("./components/token-item.js").LinkToken | import("./components/token-item.js").UserInputToken | import("./components/token-item.js").ListToken | {
3
3
  command: string;
4
- } | import("./components/TokenizedText.js").LinkToken | {
4
+ } | {
5
5
  char: string;
6
- } | import("./components/TokenizedText.js").UserInputToken | {
6
+ } | {
7
7
  subdued: string;
8
8
  } | {
9
9
  filePath: string;
10
- } | import("./components/TokenizedText.js").ListToken | import("./components/TokenizedText.js").BoldToken | {
10
+ } | import("./components/token-item.js").BoldToken | {
11
11
  info: string;
12
12
  } | {
13
13
  warn: string;
14
14
  } | {
15
15
  error: string;
16
- } | import("./components/TokenizedText.js").Token[];
16
+ } | import("./components/token-item.js").Token[];
@@ -1,4 +1,4 @@
1
- import { appendToTokenItem, tokenItemToString } from './components/TokenizedText.js';
1
+ import { appendToTokenItem, tokenItemToString } from './components/token-item.js';
2
2
  export function messageWithPunctuation(message) {
3
3
  const messageToString = tokenItemToString(message);
4
4
  return messageToString.endsWith('?') || messageToString.endsWith(':') || messageToString.endsWith('.')
@@ -1 +1 @@
1
- {"version":3,"file":"utilities.js","sourceRoot":"","sources":["../../../../src/private/node/ui/utilities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,iBAAiB,EAAa,iBAAiB,EAAC,MAAM,+BAA+B,CAAA;AAE7F,MAAM,UAAU,sBAAsB,CAAC,OAAkB;IACvD,MAAM,eAAe,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAClD,OAAO,eAAe,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,eAAe,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,eAAe,CAAC,QAAQ,CAAC,GAAG,CAAC;QACpG,CAAC,CAAC,OAAO;QACT,CAAC,CAAC,iBAAiB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;AACrC,CAAC","sourcesContent":["import {appendToTokenItem, TokenItem, tokenItemToString} from './components/TokenizedText.js'\n\nexport function messageWithPunctuation(message: TokenItem) {\n const messageToString = tokenItemToString(message)\n return messageToString.endsWith('?') || messageToString.endsWith(':') || messageToString.endsWith('.')\n ? message\n : appendToTokenItem(message, ':')\n}\n"]}
1
+ {"version":3,"file":"utilities.js","sourceRoot":"","sources":["../../../../src/private/node/ui/utilities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,iBAAiB,EAAE,iBAAiB,EAAiB,MAAM,4BAA4B,CAAA;AAE/F,MAAM,UAAU,sBAAsB,CAAC,OAAkB;IACvD,MAAM,eAAe,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAClD,OAAO,eAAe,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,eAAe,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,eAAe,CAAC,QAAQ,CAAC,GAAG,CAAC;QACpG,CAAC,CAAC,OAAO;QACT,CAAC,CAAC,iBAAiB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;AACrC,CAAC","sourcesContent":["import {appendToTokenItem, tokenItemToString, type TokenItem} from './components/token-item.js'\n\nexport function messageWithPunctuation(message: TokenItem) {\n const messageToString = tokenItemToString(message)\n return messageToString.endsWith('?') || messageToString.endsWith(':') || messageToString.endsWith('.')\n ? message\n : appendToTokenItem(message, ':')\n}\n"]}
@@ -52,26 +52,29 @@ export async function render(element, options) {
52
52
  await waitUntilExit();
53
53
  }
54
54
  export class Stdout extends EventEmitter {
55
+ columns;
56
+ rows;
57
+ frames = [];
58
+ _lastFrame;
55
59
  constructor(options) {
56
60
  super();
57
- this.frames = [];
58
- this.write = (frame) => {
59
- this.frames.push(frame);
60
- // Ink writes `this.lastOutput + '\n'` to stdout during unmount when
61
- // running in a CI environment (detected via `is-in-ci`). In debug
62
- // mode (which tests use), `lastOutput` is never updated, so the write
63
- // is just '\n', clobbering the last real rendered frame. Skip it so
64
- // that `lastFrame()` keeps returning the final rendered content.
65
- if (frame !== '\n') {
66
- this._lastFrame = frame;
67
- }
68
- };
69
- this.lastFrame = () => {
70
- return this._lastFrame;
71
- };
72
61
  this.columns = options.columns ?? 80;
73
62
  this.rows = options.rows ?? 80;
74
63
  }
64
+ write = (frame) => {
65
+ this.frames.push(frame);
66
+ // Ink writes `this.lastOutput + '\n'` to stdout during unmount when
67
+ // running in a CI environment (detected via `is-in-ci`). In debug
68
+ // mode (which tests use), `lastOutput` is never updated, so the write
69
+ // is just '\n', clobbering the last real rendered frame. Skip it so
70
+ // that `lastFrame()` keeps returning the final rendered content.
71
+ if (frame !== '\n') {
72
+ this._lastFrame = frame;
73
+ }
74
+ };
75
+ lastFrame = () => {
76
+ return this._lastFrame;
77
+ };
75
78
  }
76
79
  const renderString = (element, renderOptions) => {
77
80
  const columns = isUnitTest() ? 80 : process.stdout.columns;
@@ -1 +1 @@
1
- {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../src/private/node/ui.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,aAAa,CAAA;AAElC,OAAO,EAAC,UAAU,EAAC,MAAM,oCAAoC,CAAA;AAC7D,OAAO,EAAC,QAAQ,EAAC,MAAM,gCAAgC,CAAA;AAEvD,OAAO,KAAK,EAAE,EAAe,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAC,MAAM,OAAO,CAAA;AACtG,OAAO,EAAM,MAAM,IAAI,SAAS,EAAiB,MAAM,EAAC,MAAM,KAAK,CAAA;AAEnE,OAAO,EAAC,YAAY,EAAC,MAAM,QAAQ,CAAA;AAEnC,MAAM,iBAAiB,GAAG,aAAa,CAAmC,IAAI,CAAC,CAAA;AAE/E;;;;GAIG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,QAAQ,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAA;IAC9C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAC,QAAQ,EAA8B;IACtE,MAAM,EAAC,IAAI,EAAC,GAAG,MAAM,EAAE,CAAA;IACvB,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAyB,IAAI,CAAC,CAAA;IAE1E,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,KAAa,EAAE,EAAE;QAC7C,aAAa,CAAC,EAAC,KAAK,EAAC,CAAC,CAAA;IACxB,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;QACxB,CAAC;IACH,CAAC,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAA;IAEtB,OAAO,oBAAC,iBAAiB,CAAC,QAAQ,IAAC,KAAK,EAAE,QAAQ,IAAG,QAAQ,CAA8B,CAAA;AAC7F,CAAC;AAQD,MAAM,UAAU,UAAU,CAAC,OAAoB,EAAE,EAAC,QAAQ,GAAG,MAAM,EAAE,aAAa,EAAoB;IACpG,MAAM,EAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAC,GAAG,YAAY,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;IAE9E,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAA;IAClC,CAAC;IAED,OAAO,EAAE,CAAA;IAET,OAAO,cAAc,CAAA;AACvB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,OAAoB,EAAE,OAAuB;IACxE,MAAM,EAAC,aAAa,EAAC,GAAG,SAAS,CAAC,oBAAC,gBAAgB,QAAE,OAAO,CAAoB,EAAE;QAChF,YAAY,EAAE,CAAC,UAAU,EAAE;QAC3B,GAAG,OAAO;KACX,CAAC,CAAA;IACF,MAAM,aAAa,EAAE,CAAA;AACvB,CAAC;AAOD,MAAM,OAAO,MAAO,SAAQ,YAAY;IAMtC,YAAY,OAA0C;QACpD,KAAK,EAAE,CAAA;QAJA,WAAM,GAAa,EAAE,CAAA;QAS9B,UAAK,GAAG,CAAC,KAAa,EAAE,EAAE;YACxB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACvB,oEAAoE;YACpE,mEAAmE;YACnE,sEAAsE;YACtE,qEAAqE;YACrE,iEAAiE;YACjE,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAA;YACzB,CAAC;QACH,CAAC,CAAA;QAED,cAAS,GAAG,GAAG,EAAE;YACf,OAAO,IAAI,CAAC,UAAU,CAAA;QACxB,CAAC,CAAA;QAlBC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAA;QACpC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAA;IAChC,CAAC;CAiBF;AAED,MAAM,YAAY,GAAG,CAAC,OAAqB,EAAE,aAA6B,EAAY,EAAE;IACtF,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAA;IAC1D,8DAA8D;IAC9D,MAAM,MAAM,GAAI,aAAa,EAAE,MAAc,IAAI,IAAI,MAAM,CAAC,EAAC,OAAO,EAAC,CAAC,CAAA;IAEtE,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,EAAE;QAClC,MAAM;QACN,KAAK,EAAE,IAAI;QACX,WAAW,EAAE,KAAK;QAClB,YAAY,EAAE,KAAK;KACpB,CAAC,CAAA;IAEF,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE;QAC1B,OAAO,EAAE,QAAQ,CAAC,OAAO;KAC1B,CAAA;AACH,CAAC,CAAA;AAED,MAAM,UAAU,WAAW,CACzB,KAAa,EACb,GAAQ,EACR,IAAI,GAAG,GAAG,EAAE;IACV,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;AACjC,CAAC;IAED,IAAI,KAAK,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,gEAAgE;QAChE,IAAI,EAAE,CAAA;IACR,CAAC;AACH,CAAC","sourcesContent":["import {output} from './output.js'\nimport {Logger, LogLevel} from '../../public/node/output.js'\nimport {isUnitTest} from '../../public/node/context/local.js'\nimport {treeKill} from '../../public/node/tree-kill.js'\n\nimport React, {ReactElement, createContext, useCallback, useContext, useEffect, useState} from 'react'\nimport {Key, render as inkRender, RenderOptions, useApp} from 'ink'\n\nimport {EventEmitter} from 'events'\n\nconst CompletionContext = createContext<((error?: Error) => void) | null>(null)\n\n/**\n * Signal that the current Ink tree is done. Must be called within an\n * InkLifecycleRoot — throws if the provider is missing so lifecycle\n * bugs surface immediately instead of silently hanging.\n */\nexport function useComplete(): (error?: Error) => void {\n const complete = useContext(CompletionContext)\n if (!complete) {\n throw new Error('useComplete() called outside InkLifecycleRoot')\n }\n return complete\n}\n\n/**\n * Root wrapper for Ink trees. Owns the single `exit()` call site — children\n * signal completion via `useComplete()`, which sets state here. The `useEffect`\n * fires post-render, guaranteeing all batched state updates have been flushed\n * before the tree is torn down.\n */\nexport function InkLifecycleRoot({children}: {children: React.ReactNode}) {\n const {exit} = useApp()\n const [exitResult, setExitResult] = useState<{error?: Error} | null>(null)\n\n const complete = useCallback((error?: Error) => {\n setExitResult({error})\n }, [])\n\n useEffect(() => {\n if (exitResult !== null) {\n exit(exitResult.error)\n }\n }, [exitResult, exit])\n\n return <CompletionContext.Provider value={complete}>{children}</CompletionContext.Provider>\n}\n\ninterface RenderOnceOptions {\n logLevel?: LogLevel\n logger?: Logger\n renderOptions?: RenderOptions\n}\n\nexport function renderOnce(element: JSX.Element, {logLevel = 'info', renderOptions}: RenderOnceOptions) {\n const {output: renderedString, unmount} = renderString(element, renderOptions)\n\n if (renderedString) {\n output(renderedString, logLevel)\n }\n\n unmount()\n\n return renderedString\n}\n\nexport async function render(element: JSX.Element, options?: RenderOptions) {\n const {waitUntilExit} = inkRender(<InkLifecycleRoot>{element}</InkLifecycleRoot>, {\n patchConsole: !isUnitTest(),\n ...options,\n })\n await waitUntilExit()\n}\n\ninterface Instance {\n output: string | undefined\n unmount: () => void\n}\n\nexport class Stdout extends EventEmitter {\n columns: number\n rows: number\n readonly frames: string[] = []\n private _lastFrame?: string\n\n constructor(options: {columns?: number; rows?: number}) {\n super()\n this.columns = options.columns ?? 80\n this.rows = options.rows ?? 80\n }\n\n write = (frame: string) => {\n this.frames.push(frame)\n // Ink writes `this.lastOutput + '\\n'` to stdout during unmount when\n // running in a CI environment (detected via `is-in-ci`). In debug\n // mode (which tests use), `lastOutput` is never updated, so the write\n // is just '\\n', clobbering the last real rendered frame. Skip it so\n // that `lastFrame()` keeps returning the final rendered content.\n if (frame !== '\\n') {\n this._lastFrame = frame\n }\n }\n\n lastFrame = () => {\n return this._lastFrame\n }\n}\n\nconst renderString = (element: ReactElement, renderOptions?: RenderOptions): Instance => {\n const columns = isUnitTest() ? 80 : process.stdout.columns\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const stdout = (renderOptions?.stdout as any) ?? new Stdout({columns})\n\n const instance = inkRender(element, {\n stdout,\n debug: true,\n exitOnCtrlC: false,\n patchConsole: false,\n })\n\n return {\n output: stdout.lastFrame(),\n unmount: instance.unmount,\n }\n}\n\nexport function handleCtrlC(\n input: string,\n key: Key,\n exit = () => {\n treeKill(process.pid, 'SIGINT')\n },\n) {\n if (input === 'c' && key.ctrl) {\n // Exceptions thrown in hooks aren't caught by our errorHandler.\n exit()\n }\n}\n"]}
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../../src/private/node/ui.tsx"],"names":[],"mappings":"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","sourcesContent":["import {output} from './output.js'\nimport {Logger, LogLevel} from '../../public/node/output.js'\nimport {isUnitTest} from '../../public/node/context/local.js'\nimport {treeKill} from '../../public/node/tree-kill.js'\n\nimport React, {ReactElement, createContext, useCallback, useContext, useEffect, useState} from 'react'\nimport {Key, render as inkRender, RenderOptions, useApp} from 'ink'\n\nimport {EventEmitter} from 'events'\n\nconst CompletionContext = createContext<((error?: Error) => void) | null>(null)\n\n/**\n * Signal that the current Ink tree is done. Must be called within an\n * InkLifecycleRoot — throws if the provider is missing so lifecycle\n * bugs surface immediately instead of silently hanging.\n */\nexport function useComplete(): (error?: Error) => void {\n const complete = useContext(CompletionContext)\n if (!complete) {\n throw new Error('useComplete() called outside InkLifecycleRoot')\n }\n return complete\n}\n\n/**\n * Root wrapper for Ink trees. Owns the single `exit()` call site — children\n * signal completion via `useComplete()`, which sets state here. The `useEffect`\n * fires post-render, guaranteeing all batched state updates have been flushed\n * before the tree is torn down.\n */\nexport function InkLifecycleRoot({children}: {children: React.ReactNode}) {\n const {exit} = useApp()\n const [exitResult, setExitResult] = useState<{error?: Error} | null>(null)\n\n const complete = useCallback((error?: Error) => {\n setExitResult({error})\n }, [])\n\n useEffect(() => {\n if (exitResult !== null) {\n exit(exitResult.error)\n }\n }, [exitResult, exit])\n\n return <CompletionContext.Provider value={complete}>{children}</CompletionContext.Provider>\n}\n\ninterface RenderOnceOptions {\n logLevel?: LogLevel\n logger?: Logger\n renderOptions?: RenderOptions\n}\n\nexport function renderOnce(element: JSX.Element, {logLevel = 'info', renderOptions}: RenderOnceOptions) {\n const {output: renderedString, unmount} = renderString(element, renderOptions)\n\n if (renderedString) {\n output(renderedString, logLevel)\n }\n\n unmount()\n\n return renderedString\n}\n\nexport async function render(element: JSX.Element, options?: RenderOptions) {\n const {waitUntilExit} = inkRender(<InkLifecycleRoot>{element}</InkLifecycleRoot>, {\n patchConsole: !isUnitTest(),\n ...options,\n })\n await waitUntilExit()\n}\n\ninterface Instance {\n output: string | undefined\n unmount: () => void\n}\n\nexport class Stdout extends EventEmitter {\n columns: number\n rows: number\n readonly frames: string[] = []\n private _lastFrame?: string\n\n constructor(options: {columns?: number; rows?: number}) {\n super()\n this.columns = options.columns ?? 80\n this.rows = options.rows ?? 80\n }\n\n write = (frame: string) => {\n this.frames.push(frame)\n // Ink writes `this.lastOutput + '\\n'` to stdout during unmount when\n // running in a CI environment (detected via `is-in-ci`). In debug\n // mode (which tests use), `lastOutput` is never updated, so the write\n // is just '\\n', clobbering the last real rendered frame. Skip it so\n // that `lastFrame()` keeps returning the final rendered content.\n if (frame !== '\\n') {\n this._lastFrame = frame\n }\n }\n\n lastFrame = () => {\n return this._lastFrame\n }\n}\n\nconst renderString = (element: ReactElement, renderOptions?: RenderOptions): Instance => {\n const columns = isUnitTest() ? 80 : process.stdout.columns\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const stdout = (renderOptions?.stdout as any) ?? new Stdout({columns})\n\n const instance = inkRender(element, {\n stdout,\n debug: true,\n exitOnCtrlC: false,\n patchConsole: false,\n })\n\n return {\n output: stdout.lastFrame(),\n unmount: instance.unmount,\n }\n}\n\nexport function handleCtrlC(\n input: string,\n key: Key,\n exit = () => {\n treeKill(process.pid, 'SIGINT')\n },\n) {\n if (input === 'c' && key.ctrl) {\n // Exceptions thrown in hooks aren't caught by our errorHandler.\n exit()\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { Token, TokenItem } from '../../private/node/ui/components/TokenizedText.js';
1
+ import type { Token, TokenItem } from '../../private/node/ui/components/token-item.js';
2
2
  export type RandomNameFamily = 'business' | 'creative';
3
3
  /**
4
4
  * Generates a random name by combining an adjective and noun.