@rushstack/terminal 0.21.0 → 0.22.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 (172) hide show
  1. package/CHANGELOG.json +40 -0
  2. package/CHANGELOG.md +15 -1
  3. package/dist/tsdoc-metadata.json +1 -1
  4. package/lib-esm/AnsiEscape.js +131 -0
  5. package/lib-esm/AnsiEscape.js.map +1 -0
  6. package/lib-esm/CallbackWritable.js +27 -0
  7. package/lib-esm/CallbackWritable.js.map +1 -0
  8. package/lib-esm/Colorize.js +158 -0
  9. package/lib-esm/Colorize.js.map +1 -0
  10. package/lib-esm/ConsoleTerminalProvider.js +58 -0
  11. package/lib-esm/ConsoleTerminalProvider.js.map +1 -0
  12. package/lib-esm/DiscardStdoutTransform.js +90 -0
  13. package/lib-esm/DiscardStdoutTransform.js.map +1 -0
  14. package/lib-esm/IProblemCollector.js +4 -0
  15. package/lib-esm/IProblemCollector.js.map +1 -0
  16. package/lib-esm/ITerminal.js +4 -0
  17. package/lib-esm/ITerminal.js.map +1 -0
  18. package/lib-esm/ITerminalChunk.js +18 -0
  19. package/lib-esm/ITerminalChunk.js.map +1 -0
  20. package/lib-esm/ITerminalProvider.js +29 -0
  21. package/lib-esm/ITerminalProvider.js.map +1 -0
  22. package/lib-esm/MockWritable.js +28 -0
  23. package/lib-esm/MockWritable.js.map +1 -0
  24. package/lib-esm/NoOpTerminalProvider.js +30 -0
  25. package/lib-esm/NoOpTerminalProvider.js.map +1 -0
  26. package/lib-esm/NormalizeNewlinesTextRewriter.js +66 -0
  27. package/lib-esm/NormalizeNewlinesTextRewriter.js.map +1 -0
  28. package/lib-esm/PrefixProxyTerminalProvider.js +58 -0
  29. package/lib-esm/PrefixProxyTerminalProvider.js.map +1 -0
  30. package/lib-esm/PrintUtilities.js +146 -0
  31. package/lib-esm/PrintUtilities.js.map +1 -0
  32. package/lib-esm/ProblemCollector.js +85 -0
  33. package/lib-esm/ProblemCollector.js.map +1 -0
  34. package/lib-esm/RemoveColorsTextRewriter.js +91 -0
  35. package/lib-esm/RemoveColorsTextRewriter.js.map +1 -0
  36. package/lib-esm/SplitterTransform.js +74 -0
  37. package/lib-esm/SplitterTransform.js.map +1 -0
  38. package/lib-esm/StdioLineTransform.js +111 -0
  39. package/lib-esm/StdioLineTransform.js.map +1 -0
  40. package/lib-esm/StdioSummarizer.js +95 -0
  41. package/lib-esm/StdioSummarizer.js.map +1 -0
  42. package/lib-esm/StdioWritable.js +27 -0
  43. package/lib-esm/StdioWritable.js.map +1 -0
  44. package/lib-esm/StringBufferTerminalProvider.js +185 -0
  45. package/lib-esm/StringBufferTerminalProvider.js.map +1 -0
  46. package/lib-esm/Terminal.js +150 -0
  47. package/lib-esm/Terminal.js.map +1 -0
  48. package/lib-esm/TerminalStreamWritable.js +49 -0
  49. package/lib-esm/TerminalStreamWritable.js.map +1 -0
  50. package/lib-esm/TerminalTransform.js +53 -0
  51. package/lib-esm/TerminalTransform.js.map +1 -0
  52. package/lib-esm/TerminalWritable.js +119 -0
  53. package/lib-esm/TerminalWritable.js.map +1 -0
  54. package/lib-esm/TextRewriter.js +35 -0
  55. package/lib-esm/TextRewriter.js.map +1 -0
  56. package/lib-esm/TextRewriterTransform.js +90 -0
  57. package/lib-esm/TextRewriterTransform.js.map +1 -0
  58. package/lib-esm/index.js +38 -0
  59. package/lib-esm/index.js.map +1 -0
  60. package/package.json +30 -6
  61. /package/{lib → lib-commonjs}/AnsiEscape.js +0 -0
  62. /package/{lib → lib-commonjs}/AnsiEscape.js.map +0 -0
  63. /package/{lib → lib-commonjs}/CallbackWritable.js +0 -0
  64. /package/{lib → lib-commonjs}/CallbackWritable.js.map +0 -0
  65. /package/{lib → lib-commonjs}/Colorize.js +0 -0
  66. /package/{lib → lib-commonjs}/Colorize.js.map +0 -0
  67. /package/{lib → lib-commonjs}/ConsoleTerminalProvider.js +0 -0
  68. /package/{lib → lib-commonjs}/ConsoleTerminalProvider.js.map +0 -0
  69. /package/{lib → lib-commonjs}/DiscardStdoutTransform.js +0 -0
  70. /package/{lib → lib-commonjs}/DiscardStdoutTransform.js.map +0 -0
  71. /package/{lib → lib-commonjs}/IProblemCollector.js +0 -0
  72. /package/{lib → lib-commonjs}/IProblemCollector.js.map +0 -0
  73. /package/{lib → lib-commonjs}/ITerminal.js +0 -0
  74. /package/{lib → lib-commonjs}/ITerminal.js.map +0 -0
  75. /package/{lib → lib-commonjs}/ITerminalChunk.js +0 -0
  76. /package/{lib → lib-commonjs}/ITerminalChunk.js.map +0 -0
  77. /package/{lib → lib-commonjs}/ITerminalProvider.js +0 -0
  78. /package/{lib → lib-commonjs}/ITerminalProvider.js.map +0 -0
  79. /package/{lib → lib-commonjs}/MockWritable.js +0 -0
  80. /package/{lib → lib-commonjs}/MockWritable.js.map +0 -0
  81. /package/{lib → lib-commonjs}/NoOpTerminalProvider.js +0 -0
  82. /package/{lib → lib-commonjs}/NoOpTerminalProvider.js.map +0 -0
  83. /package/{lib → lib-commonjs}/NormalizeNewlinesTextRewriter.js +0 -0
  84. /package/{lib → lib-commonjs}/NormalizeNewlinesTextRewriter.js.map +0 -0
  85. /package/{lib → lib-commonjs}/PrefixProxyTerminalProvider.js +0 -0
  86. /package/{lib → lib-commonjs}/PrefixProxyTerminalProvider.js.map +0 -0
  87. /package/{lib → lib-commonjs}/PrintUtilities.js +0 -0
  88. /package/{lib → lib-commonjs}/PrintUtilities.js.map +0 -0
  89. /package/{lib → lib-commonjs}/ProblemCollector.js +0 -0
  90. /package/{lib → lib-commonjs}/ProblemCollector.js.map +0 -0
  91. /package/{lib → lib-commonjs}/RemoveColorsTextRewriter.js +0 -0
  92. /package/{lib → lib-commonjs}/RemoveColorsTextRewriter.js.map +0 -0
  93. /package/{lib → lib-commonjs}/SplitterTransform.js +0 -0
  94. /package/{lib → lib-commonjs}/SplitterTransform.js.map +0 -0
  95. /package/{lib → lib-commonjs}/StdioLineTransform.js +0 -0
  96. /package/{lib → lib-commonjs}/StdioLineTransform.js.map +0 -0
  97. /package/{lib → lib-commonjs}/StdioSummarizer.js +0 -0
  98. /package/{lib → lib-commonjs}/StdioSummarizer.js.map +0 -0
  99. /package/{lib → lib-commonjs}/StdioWritable.js +0 -0
  100. /package/{lib → lib-commonjs}/StdioWritable.js.map +0 -0
  101. /package/{lib → lib-commonjs}/StringBufferTerminalProvider.js +0 -0
  102. /package/{lib → lib-commonjs}/StringBufferTerminalProvider.js.map +0 -0
  103. /package/{lib → lib-commonjs}/Terminal.js +0 -0
  104. /package/{lib → lib-commonjs}/Terminal.js.map +0 -0
  105. /package/{lib → lib-commonjs}/TerminalStreamWritable.js +0 -0
  106. /package/{lib → lib-commonjs}/TerminalStreamWritable.js.map +0 -0
  107. /package/{lib → lib-commonjs}/TerminalTransform.js +0 -0
  108. /package/{lib → lib-commonjs}/TerminalTransform.js.map +0 -0
  109. /package/{lib → lib-commonjs}/TerminalWritable.js +0 -0
  110. /package/{lib → lib-commonjs}/TerminalWritable.js.map +0 -0
  111. /package/{lib → lib-commonjs}/TextRewriter.js +0 -0
  112. /package/{lib → lib-commonjs}/TextRewriter.js.map +0 -0
  113. /package/{lib → lib-commonjs}/TextRewriterTransform.js +0 -0
  114. /package/{lib → lib-commonjs}/TextRewriterTransform.js.map +0 -0
  115. /package/{lib → lib-commonjs}/index.js +0 -0
  116. /package/{lib → lib-commonjs}/index.js.map +0 -0
  117. /package/{lib → lib-dts}/AnsiEscape.d.ts +0 -0
  118. /package/{lib → lib-dts}/AnsiEscape.d.ts.map +0 -0
  119. /package/{lib → lib-dts}/CallbackWritable.d.ts +0 -0
  120. /package/{lib → lib-dts}/CallbackWritable.d.ts.map +0 -0
  121. /package/{lib → lib-dts}/Colorize.d.ts +0 -0
  122. /package/{lib → lib-dts}/Colorize.d.ts.map +0 -0
  123. /package/{lib → lib-dts}/ConsoleTerminalProvider.d.ts +0 -0
  124. /package/{lib → lib-dts}/ConsoleTerminalProvider.d.ts.map +0 -0
  125. /package/{lib → lib-dts}/DiscardStdoutTransform.d.ts +0 -0
  126. /package/{lib → lib-dts}/DiscardStdoutTransform.d.ts.map +0 -0
  127. /package/{lib → lib-dts}/IProblemCollector.d.ts +0 -0
  128. /package/{lib → lib-dts}/IProblemCollector.d.ts.map +0 -0
  129. /package/{lib → lib-dts}/ITerminal.d.ts +0 -0
  130. /package/{lib → lib-dts}/ITerminal.d.ts.map +0 -0
  131. /package/{lib → lib-dts}/ITerminalChunk.d.ts +0 -0
  132. /package/{lib → lib-dts}/ITerminalChunk.d.ts.map +0 -0
  133. /package/{lib → lib-dts}/ITerminalProvider.d.ts +0 -0
  134. /package/{lib → lib-dts}/ITerminalProvider.d.ts.map +0 -0
  135. /package/{lib → lib-dts}/MockWritable.d.ts +0 -0
  136. /package/{lib → lib-dts}/MockWritable.d.ts.map +0 -0
  137. /package/{lib → lib-dts}/NoOpTerminalProvider.d.ts +0 -0
  138. /package/{lib → lib-dts}/NoOpTerminalProvider.d.ts.map +0 -0
  139. /package/{lib → lib-dts}/NormalizeNewlinesTextRewriter.d.ts +0 -0
  140. /package/{lib → lib-dts}/NormalizeNewlinesTextRewriter.d.ts.map +0 -0
  141. /package/{lib → lib-dts}/PrefixProxyTerminalProvider.d.ts +0 -0
  142. /package/{lib → lib-dts}/PrefixProxyTerminalProvider.d.ts.map +0 -0
  143. /package/{lib → lib-dts}/PrintUtilities.d.ts +0 -0
  144. /package/{lib → lib-dts}/PrintUtilities.d.ts.map +0 -0
  145. /package/{lib → lib-dts}/ProblemCollector.d.ts +0 -0
  146. /package/{lib → lib-dts}/ProblemCollector.d.ts.map +0 -0
  147. /package/{lib → lib-dts}/RemoveColorsTextRewriter.d.ts +0 -0
  148. /package/{lib → lib-dts}/RemoveColorsTextRewriter.d.ts.map +0 -0
  149. /package/{lib → lib-dts}/SplitterTransform.d.ts +0 -0
  150. /package/{lib → lib-dts}/SplitterTransform.d.ts.map +0 -0
  151. /package/{lib → lib-dts}/StdioLineTransform.d.ts +0 -0
  152. /package/{lib → lib-dts}/StdioLineTransform.d.ts.map +0 -0
  153. /package/{lib → lib-dts}/StdioSummarizer.d.ts +0 -0
  154. /package/{lib → lib-dts}/StdioSummarizer.d.ts.map +0 -0
  155. /package/{lib → lib-dts}/StdioWritable.d.ts +0 -0
  156. /package/{lib → lib-dts}/StdioWritable.d.ts.map +0 -0
  157. /package/{lib → lib-dts}/StringBufferTerminalProvider.d.ts +0 -0
  158. /package/{lib → lib-dts}/StringBufferTerminalProvider.d.ts.map +0 -0
  159. /package/{lib → lib-dts}/Terminal.d.ts +0 -0
  160. /package/{lib → lib-dts}/Terminal.d.ts.map +0 -0
  161. /package/{lib → lib-dts}/TerminalStreamWritable.d.ts +0 -0
  162. /package/{lib → lib-dts}/TerminalStreamWritable.d.ts.map +0 -0
  163. /package/{lib → lib-dts}/TerminalTransform.d.ts +0 -0
  164. /package/{lib → lib-dts}/TerminalTransform.d.ts.map +0 -0
  165. /package/{lib → lib-dts}/TerminalWritable.d.ts +0 -0
  166. /package/{lib → lib-dts}/TerminalWritable.d.ts.map +0 -0
  167. /package/{lib → lib-dts}/TextRewriter.d.ts +0 -0
  168. /package/{lib → lib-dts}/TextRewriter.d.ts.map +0 -0
  169. /package/{lib → lib-dts}/TextRewriterTransform.d.ts +0 -0
  170. /package/{lib → lib-dts}/TextRewriterTransform.d.ts.map +0 -0
  171. /package/{lib → lib-dts}/index.d.ts +0 -0
  172. /package/{lib → lib-dts}/index.d.ts.map +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITerminal.js","sourceRoot":"","sources":["../src/ITerminal.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,2DAA2D","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { ITerminalProvider } from './ITerminalProvider';\n\n/**\n * @beta\n */\nexport interface ITerminalWriteOptions {\n /**\n * If set to true, SGR parameters will not be replaced by the terminal\n * standard (i.e. - red for errors, yellow for warnings).\n */\n doNotOverrideSgrCodes?: boolean;\n}\n\n/**\n * @beta\n */\nexport type TerminalWriteParameters = string[] | [...string[], ITerminalWriteOptions];\n\n/**\n * @beta\n */\nexport interface ITerminal {\n /**\n * Subscribe a new terminal provider.\n */\n registerProvider(provider: ITerminalProvider): void;\n\n /**\n * Unsubscribe a terminal provider. If the provider isn't subscribed, this function does nothing.\n */\n unregisterProvider(provider: ITerminalProvider): void;\n\n /**\n * Write a generic message to the terminal\n */\n write(...messageParts: TerminalWriteParameters): void;\n\n /**\n * Write a generic message to the terminal, followed by a newline\n */\n writeLine(...messageParts: TerminalWriteParameters): void;\n\n /**\n * Write a warning message to the console with yellow text.\n *\n * @remarks\n * The yellow color takes precedence over any other foreground colors set.\n */\n writeWarning(...messageParts: TerminalWriteParameters): void;\n\n /**\n * Write a warning message to the console with yellow text, followed by a newline.\n *\n * @remarks\n * The yellow color takes precedence over any other foreground colors set.\n */\n writeWarningLine(...messageParts: TerminalWriteParameters): void;\n\n /**\n * Write an error message to the console with red text.\n *\n * @remarks\n * The red color takes precedence over any other foreground colors set.\n */\n writeError(...messageParts: TerminalWriteParameters): void;\n\n /**\n * Write an error message to the console with red text, followed by a newline.\n *\n * @remarks\n * The red color takes precedence over any other foreground colors set.\n */\n writeErrorLine(...messageParts: TerminalWriteParameters): void;\n\n /**\n * Write a verbose-level message.\n */\n writeVerbose(...messageParts: TerminalWriteParameters): void;\n\n /**\n * Write a verbose-level message followed by a newline.\n */\n writeVerboseLine(...messageParts: TerminalWriteParameters): void;\n\n /**\n * Write a debug-level message.\n */\n writeDebug(...messageParts: TerminalWriteParameters): void;\n\n /**\n * Write a debug-level message followed by a newline.\n */\n writeDebugLine(...messageParts: TerminalWriteParameters): void;\n}\n"]}
@@ -0,0 +1,18 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2
+ // See LICENSE in the project root for license information.
3
+ /**
4
+ * Specifies the kind of data represented by a {@link ITerminalChunk} object.
5
+ * @public
6
+ */
7
+ export var TerminalChunkKind;
8
+ (function (TerminalChunkKind) {
9
+ /**
10
+ * Indicates a `ITerminalChunk` object representing `stdout` console output.
11
+ */
12
+ TerminalChunkKind["Stdout"] = "O";
13
+ /**
14
+ * Indicates a `ITerminalChunk` object representing `stderr` console output.
15
+ */
16
+ TerminalChunkKind["Stderr"] = "E";
17
+ })(TerminalChunkKind || (TerminalChunkKind = {}));
18
+ //# sourceMappingURL=ITerminalChunk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITerminalChunk.js","sourceRoot":"","sources":["../src/ITerminalChunk.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,2DAA2D;AAE3D;;;GAGG;AACH,MAAM,CAAN,IAAY,iBAUX;AAVD,WAAY,iBAAiB;IAC3B;;OAEG;IACH,iCAAY,CAAA;IAEZ;;OAEG;IACH,iCAAY,CAAA;AACd,CAAC,EAVW,iBAAiB,KAAjB,iBAAiB,QAU5B","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * Specifies the kind of data represented by a {@link ITerminalChunk} object.\n * @public\n */\nexport enum TerminalChunkKind {\n /**\n * Indicates a `ITerminalChunk` object representing `stdout` console output.\n */\n Stdout = 'O',\n\n /**\n * Indicates a `ITerminalChunk` object representing `stderr` console output.\n */\n Stderr = 'E'\n}\n\n/**\n * Represents a chunk of output that will ultimately be written to a {@link TerminalWritable}.\n *\n * @remarks\n * Today `ITerminalChunk` represents the `stdout` and `stderr` text streams. In the future,\n * we plan to expand it to include other console UI elements such as instructions for displaying\n * an interactive progress bar. We may also add other metadata, for example tracking whether\n * the `text` string is known to contain color codes or not.\n *\n * The `ITerminalChunk` object should be considered to be immutable once it is created.\n * For example, {@link SplitterTransform} may pass the same chunk to multiple destinations.\n *\n * @public\n */\nexport interface ITerminalChunk {\n /**\n * Indicates the kind of information stored in this chunk.\n *\n * @remarks\n * More kinds will be introduced in the future. Implementors of\n * {@link TerminalWritable.onWriteChunk} should ignore unrecognized `TerminalChunkKind`\n * values. `TerminalTransform` implementors should pass along unrecognized chunks\n * rather than discarding them.\n */\n kind: TerminalChunkKind;\n\n /**\n * The next chunk of text from the `stderr` or `stdout` stream.\n */\n text: string;\n}\n"]}
@@ -0,0 +1,29 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2
+ // See LICENSE in the project root for license information.
3
+ /**
4
+ * Similar to many popular logging packages, terminal providers support a range of message
5
+ * severities. These severities have built-in formatting defaults in the Terminal object
6
+ * (warnings are yellow, errors are red, etc.).
7
+ *
8
+ * Terminal providers may choose to suppress certain messages based on their severity,
9
+ * or to route some messages to other providers or not based on severity.
10
+ *
11
+ * Severity | Purpose
12
+ * --------- | -------
13
+ * error | Build errors and fatal issues
14
+ * warning | Not necessarily fatal, but indicate a problem the user should fix
15
+ * log | Informational messages
16
+ * verbose | Additional information that may not always be necessary
17
+ * debug | Highest detail level, best used for troubleshooting information
18
+ *
19
+ * @beta
20
+ */
21
+ export var TerminalProviderSeverity;
22
+ (function (TerminalProviderSeverity) {
23
+ TerminalProviderSeverity[TerminalProviderSeverity["log"] = 0] = "log";
24
+ TerminalProviderSeverity[TerminalProviderSeverity["warning"] = 1] = "warning";
25
+ TerminalProviderSeverity[TerminalProviderSeverity["error"] = 2] = "error";
26
+ TerminalProviderSeverity[TerminalProviderSeverity["verbose"] = 3] = "verbose";
27
+ TerminalProviderSeverity[TerminalProviderSeverity["debug"] = 4] = "debug";
28
+ })(TerminalProviderSeverity || (TerminalProviderSeverity = {}));
29
+ //# sourceMappingURL=ITerminalProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITerminalProvider.js","sourceRoot":"","sources":["../src/ITerminalProvider.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,2DAA2D;AAE3D;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAN,IAAY,wBAMX;AAND,WAAY,wBAAwB;IAClC,qEAAG,CAAA;IACH,6EAAO,CAAA;IACP,yEAAK,CAAA;IACL,6EAAO,CAAA;IACP,yEAAK,CAAA;AACP,CAAC,EANW,wBAAwB,KAAxB,wBAAwB,QAMnC","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * Similar to many popular logging packages, terminal providers support a range of message\n * severities. These severities have built-in formatting defaults in the Terminal object\n * (warnings are yellow, errors are red, etc.).\n *\n * Terminal providers may choose to suppress certain messages based on their severity,\n * or to route some messages to other providers or not based on severity.\n *\n * Severity | Purpose\n * --------- | -------\n * error | Build errors and fatal issues\n * warning | Not necessarily fatal, but indicate a problem the user should fix\n * log | Informational messages\n * verbose | Additional information that may not always be necessary\n * debug | Highest detail level, best used for troubleshooting information\n *\n * @beta\n */\nexport enum TerminalProviderSeverity {\n log,\n warning,\n error,\n verbose,\n debug\n}\n\n/**\n * Implement the interface to create a terminal provider. Terminal providers\n * can be registered to a {@link Terminal} instance to receive messages.\n *\n * @beta\n */\nexport interface ITerminalProvider {\n /**\n * This property should return true only if the terminal provider supports\n * rendering console colors.\n */\n supportsColor: boolean;\n\n /**\n * This property should return the newline character the terminal provider\n * expects.\n */\n eolCharacter: string;\n\n /**\n * This function gets called on every terminal provider upon every\n * message function call on the terminal instance.\n *\n * @param data - The terminal message.\n * @param severity - The message severity. Terminal providers can\n * route different kinds of messages to different streams and may choose\n * to ignore verbose or debug messages.\n */\n write(data: string, severity: TerminalProviderSeverity): void;\n}\n"]}
@@ -0,0 +1,28 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2
+ // See LICENSE in the project root for license information.
3
+ import { AnsiEscape } from './AnsiEscape';
4
+ import { TerminalWritable } from './TerminalWritable';
5
+ /**
6
+ * A {@link TerminalWritable} subclass for use by unit tests.
7
+ *
8
+ * @beta
9
+ */
10
+ export class MockWritable extends TerminalWritable {
11
+ constructor() {
12
+ super(...arguments);
13
+ this.chunks = [];
14
+ }
15
+ onWriteChunk(chunk) {
16
+ this.chunks.push(chunk);
17
+ }
18
+ reset() {
19
+ this.chunks.length = 0;
20
+ }
21
+ getAllOutput() {
22
+ return AnsiEscape.formatForTests(this.chunks.map((x) => x.text).join(''));
23
+ }
24
+ getFormattedChunks() {
25
+ return this.chunks.map((x) => ({ ...x, text: AnsiEscape.formatForTests(x.text) }));
26
+ }
27
+ }
28
+ //# sourceMappingURL=MockWritable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MockWritable.js","sourceRoot":"","sources":["../src/MockWritable.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,2DAA2D;AAE3D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD;;;;GAIG;AACH,MAAM,OAAO,YAAa,SAAQ,gBAAgB;IAAlD;;QACkB,WAAM,GAAqB,EAAE,CAAC;IAiBhD,CAAC;IAfW,YAAY,CAAC,KAAqB;QAC1C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAEM,KAAK;QACV,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IACzB,CAAC;IAEM,YAAY;QACjB,OAAO,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5E,CAAC;IAEM,kBAAkB;QACvB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAmB,CAAC,CAAC;IACvG,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { AnsiEscape } from './AnsiEscape';\nimport type { ITerminalChunk } from './ITerminalChunk';\nimport { TerminalWritable } from './TerminalWritable';\n\n/**\n * A {@link TerminalWritable} subclass for use by unit tests.\n *\n * @beta\n */\nexport class MockWritable extends TerminalWritable {\n public readonly chunks: ITerminalChunk[] = [];\n\n protected onWriteChunk(chunk: ITerminalChunk): void {\n this.chunks.push(chunk);\n }\n\n public reset(): void {\n this.chunks.length = 0;\n }\n\n public getAllOutput(): string {\n return AnsiEscape.formatForTests(this.chunks.map((x) => x.text).join(''));\n }\n\n public getFormattedChunks(): ITerminalChunk[] {\n return this.chunks.map((x) => ({ ...x, text: AnsiEscape.formatForTests(x.text) }) as ITerminalChunk);\n }\n}\n"]}
@@ -0,0 +1,30 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2
+ // See LICENSE in the project root for license information.
3
+ /**
4
+ * Terminal provider that stores written data in buffers separated by severity.
5
+ * This terminal provider is designed to be used when code that prints to a terminal
6
+ * is being unit tested.
7
+ *
8
+ * @beta
9
+ */
10
+ export class NoOpTerminalProvider {
11
+ /**
12
+ * {@inheritDoc ITerminalProvider.write}
13
+ */
14
+ write(data, severity) {
15
+ // no-op
16
+ }
17
+ /**
18
+ * {@inheritDoc ITerminalProvider.eolCharacter}
19
+ */
20
+ get eolCharacter() {
21
+ return '\n';
22
+ }
23
+ /**
24
+ * {@inheritDoc ITerminalProvider.supportsColor}
25
+ */
26
+ get supportsColor() {
27
+ return false;
28
+ }
29
+ }
30
+ //# sourceMappingURL=NoOpTerminalProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NoOpTerminalProvider.js","sourceRoot":"","sources":["../src/NoOpTerminalProvider.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,2DAA2D;AAI3D;;;;;;GAMG;AACH,MAAM,OAAO,oBAAoB;IAC/B;;OAEG;IACI,KAAK,CAAC,IAAY,EAAE,QAAkC;QAC3D,QAAQ;IACV,CAAC;IAED;;OAEG;IACH,IAAW,YAAY;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,IAAW,aAAa;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport type { ITerminalProvider, TerminalProviderSeverity } from './ITerminalProvider';\n\n/**\n * Terminal provider that stores written data in buffers separated by severity.\n * This terminal provider is designed to be used when code that prints to a terminal\n * is being unit tested.\n *\n * @beta\n */\nexport class NoOpTerminalProvider implements ITerminalProvider {\n /**\n * {@inheritDoc ITerminalProvider.write}\n */\n public write(data: string, severity: TerminalProviderSeverity): void {\n // no-op\n }\n\n /**\n * {@inheritDoc ITerminalProvider.eolCharacter}\n */\n public get eolCharacter(): string {\n return '\\n';\n }\n\n /**\n * {@inheritDoc ITerminalProvider.supportsColor}\n */\n public get supportsColor(): boolean {\n return false;\n }\n}\n"]}
@@ -0,0 +1,66 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2
+ // See LICENSE in the project root for license information.
3
+ import { Text } from '@rushstack/node-core-library';
4
+ import { TextRewriter } from './TextRewriter';
5
+ /**
6
+ * For use with {@link TextRewriterTransform}, this rewriter converts all newlines to
7
+ * a standard format.
8
+ *
9
+ * @public
10
+ */
11
+ export class NormalizeNewlinesTextRewriter extends TextRewriter {
12
+ constructor(options) {
13
+ super();
14
+ this.newlineKind = options.newlineKind;
15
+ this.newline = Text.getNewline(options.newlineKind);
16
+ this.ensureNewlineAtEnd = !!options.ensureNewlineAtEnd;
17
+ }
18
+ initialize() {
19
+ return {
20
+ characterToIgnore: '',
21
+ incompleteLine: false
22
+ };
23
+ }
24
+ process(unknownState, text) {
25
+ const state = unknownState;
26
+ let result = '';
27
+ if (text.length > 0) {
28
+ let i = 0;
29
+ do {
30
+ const c = text[i];
31
+ ++i;
32
+ if (c === state.characterToIgnore) {
33
+ state.characterToIgnore = '';
34
+ }
35
+ else if (c === '\r') {
36
+ result += this.newline;
37
+ state.characterToIgnore = '\n';
38
+ state.incompleteLine = false;
39
+ }
40
+ else if (c === '\n') {
41
+ result += this.newline;
42
+ state.characterToIgnore = '\r';
43
+ state.incompleteLine = false;
44
+ }
45
+ else {
46
+ result += c;
47
+ state.characterToIgnore = '';
48
+ state.incompleteLine = true;
49
+ }
50
+ } while (i < text.length);
51
+ }
52
+ return result;
53
+ }
54
+ close(unknownState) {
55
+ const state = unknownState;
56
+ state.characterToIgnore = '';
57
+ if (state.incompleteLine) {
58
+ state.incompleteLine = false;
59
+ return this.newline;
60
+ }
61
+ else {
62
+ return '';
63
+ }
64
+ }
65
+ }
66
+ //# sourceMappingURL=NormalizeNewlinesTextRewriter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NormalizeNewlinesTextRewriter.js","sourceRoot":"","sources":["../src/NormalizeNewlinesTextRewriter.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,2DAA2D;AAE3D,OAAO,EAAE,IAAI,EAAoB,MAAM,8BAA8B,CAAC;AAEtE,OAAO,EAAE,YAAY,EAA0B,MAAM,gBAAgB,CAAC;AA6BtE;;;;;GAKG;AACH,MAAM,OAAO,6BAA8B,SAAQ,YAAY;IAY7D,YAAmB,OAA8C;QAC/D,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACpD,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC;IACzD,CAAC;IAEM,UAAU;QACf,OAAO;YACL,iBAAiB,EAAE,EAAE;YACrB,cAAc,EAAE,KAAK;SACiB,CAAC;IAC3C,CAAC;IAEM,OAAO,CAAC,YAA+B,EAAE,IAAY;QAC1D,MAAM,KAAK,GAAwC,YAAmD,CAAC;QAEvG,IAAI,MAAM,GAAW,EAAE,CAAC;QAExB,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,GAAW,CAAC,CAAC;YAElB,GAAG,CAAC;gBACF,MAAM,CAAC,GAAW,IAAI,CAAC,CAAC,CAAC,CAAC;gBAC1B,EAAE,CAAC,CAAC;gBAEJ,IAAI,CAAC,KAAK,KAAK,CAAC,iBAAiB,EAAE,CAAC;oBAClC,KAAK,CAAC,iBAAiB,GAAG,EAAE,CAAC;gBAC/B,CAAC;qBAAM,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;oBACtB,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC;oBACvB,KAAK,CAAC,iBAAiB,GAAG,IAAI,CAAC;oBAC/B,KAAK,CAAC,cAAc,GAAG,KAAK,CAAC;gBAC/B,CAAC;qBAAM,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;oBACtB,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC;oBACvB,KAAK,CAAC,iBAAiB,GAAG,IAAI,CAAC;oBAC/B,KAAK,CAAC,cAAc,GAAG,KAAK,CAAC;gBAC/B,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,CAAC,CAAC;oBACZ,KAAK,CAAC,iBAAiB,GAAG,EAAE,CAAC;oBAC7B,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC;gBAC9B,CAAC;YACH,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE;QAC5B,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAEM,KAAK,CAAC,YAA+B;QAC1C,MAAM,KAAK,GAAwC,YAAmD,CAAC;QACvG,KAAK,CAAC,iBAAiB,GAAG,EAAE,CAAC;QAE7B,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;YACzB,KAAK,CAAC,cAAc,GAAG,KAAK,CAAC;YAC7B,OAAO,IAAI,CAAC,OAAO,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { Text, type NewlineKind } from '@rushstack/node-core-library';\n\nimport { TextRewriter, type TextRewriterState } from './TextRewriter';\n\ninterface INormalizeNewlinesTextRewriterState extends TextRewriterState {\n characterToIgnore: string;\n incompleteLine: boolean;\n}\n\n/**\n * Constructor options for {@link NormalizeNewlinesTextRewriter}\n *\n * @public\n */\nexport interface INormalizeNewlinesTextRewriterOptions {\n /**\n * Specifies how newlines should be represented in the output stream.\n */\n newlineKind: NewlineKind;\n\n /**\n * If `true`, then `NormalizeNewlinesTextRewriter.close()` will append a newline to\n * the output if it ends with an incomplete line.\n *\n * @remarks\n * If the output is an empty string, then a newline will NOT be appended,\n * because writing an empty string does not produce an incomplete line.\n */\n ensureNewlineAtEnd?: boolean;\n}\n\n/**\n * For use with {@link TextRewriterTransform}, this rewriter converts all newlines to\n * a standard format.\n *\n * @public\n */\nexport class NormalizeNewlinesTextRewriter extends TextRewriter {\n /** {@inheritDoc INormalizeNewlinesTextRewriterOptions.newlineKind} */\n public readonly newlineKind: NewlineKind;\n\n /**\n * The specific character sequence that will be used when appending newlines.\n */\n public readonly newline: string;\n\n /** {@inheritDoc INormalizeNewlinesTextRewriterOptions.ensureNewlineAtEnd} */\n public readonly ensureNewlineAtEnd: boolean;\n\n public constructor(options: INormalizeNewlinesTextRewriterOptions) {\n super();\n this.newlineKind = options.newlineKind;\n this.newline = Text.getNewline(options.newlineKind);\n this.ensureNewlineAtEnd = !!options.ensureNewlineAtEnd;\n }\n\n public initialize(): TextRewriterState {\n return {\n characterToIgnore: '',\n incompleteLine: false\n } as INormalizeNewlinesTextRewriterState;\n }\n\n public process(unknownState: TextRewriterState, text: string): string {\n const state: INormalizeNewlinesTextRewriterState = unknownState as INormalizeNewlinesTextRewriterState;\n\n let result: string = '';\n\n if (text.length > 0) {\n let i: number = 0;\n\n do {\n const c: string = text[i];\n ++i;\n\n if (c === state.characterToIgnore) {\n state.characterToIgnore = '';\n } else if (c === '\\r') {\n result += this.newline;\n state.characterToIgnore = '\\n';\n state.incompleteLine = false;\n } else if (c === '\\n') {\n result += this.newline;\n state.characterToIgnore = '\\r';\n state.incompleteLine = false;\n } else {\n result += c;\n state.characterToIgnore = '';\n state.incompleteLine = true;\n }\n } while (i < text.length);\n }\n\n return result;\n }\n\n public close(unknownState: TextRewriterState): string {\n const state: INormalizeNewlinesTextRewriterState = unknownState as INormalizeNewlinesTextRewriterState;\n state.characterToIgnore = '';\n\n if (state.incompleteLine) {\n state.incompleteLine = false;\n return this.newline;\n } else {\n return '';\n }\n }\n}\n"]}
@@ -0,0 +1,58 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2
+ // See LICENSE in the project root for license information.
3
+ import { Text } from '@rushstack/node-core-library';
4
+ /**
5
+ * Wraps an existing {@link ITerminalProvider} that prefixes each line of output with a specified
6
+ * prefix string.
7
+ *
8
+ * @beta
9
+ */
10
+ export class PrefixProxyTerminalProvider {
11
+ constructor(options) {
12
+ const { terminalProvider } = options;
13
+ this._parentTerminalProvider = terminalProvider;
14
+ if (options.prefix !== undefined) {
15
+ const { prefix } = options;
16
+ this._getPrefix = () => prefix;
17
+ }
18
+ else {
19
+ const { getPrefix } = options;
20
+ this._getPrefix = getPrefix;
21
+ }
22
+ this._isOnNewline = true;
23
+ this._newlineRegex = new RegExp(`${Text.escapeRegExp(terminalProvider.eolCharacter)}|\\n`, 'g');
24
+ }
25
+ /** @override */
26
+ get supportsColor() {
27
+ return this._parentTerminalProvider.supportsColor;
28
+ }
29
+ /** @override */
30
+ get eolCharacter() {
31
+ return this._parentTerminalProvider.eolCharacter;
32
+ }
33
+ /** @override */
34
+ write(data, severity) {
35
+ // We need to track newlines to ensure that the prefix is added to each line
36
+ let currentIndex = 0;
37
+ let newlineMatch;
38
+ while ((newlineMatch = this._newlineRegex.exec(data))) {
39
+ // Extract the line, add the prefix, and write it out with the newline
40
+ const newlineIndex = newlineMatch.index;
41
+ const newIndex = newlineIndex + newlineMatch[0].length;
42
+ const prefix = this._isOnNewline ? this._getPrefix() : '';
43
+ const dataToWrite = `${prefix}${data.substring(currentIndex, newIndex)}`;
44
+ this._parentTerminalProvider.write(dataToWrite, severity);
45
+ // Update the currentIndex to start the search from the char after the newline
46
+ currentIndex = newIndex;
47
+ this._isOnNewline = true;
48
+ }
49
+ // The remaining data is not postfixed by a newline, so write out the data and set _isNewline to false
50
+ const remainingData = data.substring(currentIndex);
51
+ if (remainingData.length) {
52
+ const prefix = this._isOnNewline ? this._getPrefix() : '';
53
+ this._parentTerminalProvider.write(`${prefix}${remainingData}`, severity);
54
+ this._isOnNewline = false;
55
+ }
56
+ }
57
+ }
58
+ //# sourceMappingURL=PrefixProxyTerminalProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrefixProxyTerminalProvider.js","sourceRoot":"","sources":["../src/PrefixProxyTerminalProvider.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,2DAA2D;AAE3D,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAC;AA8CpD;;;;;GAKG;AACH,MAAM,OAAO,2BAA2B;IAMtC,YAAmB,OAA4C;QAC7D,MAAM,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC;QAErC,IAAI,CAAC,uBAAuB,GAAG,gBAAgB,CAAC;QAEhD,IAAK,OAAqD,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChF,MAAM,EAAE,MAAM,EAAE,GAAG,OAAoD,CAAC;YACxE,IAAI,CAAC,UAAU,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,MAAM,EAAE,SAAS,EAAE,GAAG,OAAqD,CAAC;YAC5E,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC9B,CAAC;QAED,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAEzB,IAAI,CAAC,aAAa,GAAG,IAAI,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAClG,CAAC;IAED,gBAAgB;IAChB,IAAW,aAAa;QACtB,OAAO,IAAI,CAAC,uBAAuB,CAAC,aAAa,CAAC;IACpD,CAAC;IAED,gBAAgB;IAChB,IAAW,YAAY;QACrB,OAAO,IAAI,CAAC,uBAAuB,CAAC,YAAY,CAAC;IACnD,CAAC;IAED,gBAAgB;IACT,KAAK,CAAC,IAAY,EAAE,QAAkC;QAC3D,4EAA4E;QAC5E,IAAI,YAAY,GAAW,CAAC,CAAC;QAC7B,IAAI,YAAoC,CAAC;QAEzC,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACtD,sEAAsE;YACtE,MAAM,YAAY,GAAW,YAAY,CAAC,KAAK,CAAC;YAChD,MAAM,QAAQ,GAAW,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YAC/D,MAAM,MAAM,GAAW,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,MAAM,WAAW,GAAW,GAAG,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,QAAQ,CAAC,EAAE,CAAC;YACjF,IAAI,CAAC,uBAAuB,CAAC,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;YAC1D,8EAA8E;YAC9E,YAAY,GAAG,QAAQ,CAAC;YACxB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;QAED,sGAAsG;QACtG,MAAM,aAAa,GAAW,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAC3D,IAAI,aAAa,CAAC,MAAM,EAAE,CAAC;YACzB,MAAM,MAAM,GAAW,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,IAAI,CAAC,uBAAuB,CAAC,KAAK,CAAC,GAAG,MAAM,GAAG,aAAa,EAAE,EAAE,QAAQ,CAAC,CAAC;YAC1E,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC5B,CAAC;IACH,CAAC;CACF","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { Text } from '@rushstack/node-core-library';\n\nimport type { ITerminalProvider, TerminalProviderSeverity } from './ITerminalProvider';\n\n/**\n * @beta\n */\nexport interface IPrefixProxyTerminalProviderOptionsBase {\n /**\n * The {@link ITerminalProvider} that will be wrapped.\n */\n terminalProvider: ITerminalProvider;\n}\n\n/**\n * Options for {@link PrefixProxyTerminalProvider}, with a static prefix.\n *\n * @beta\n */\nexport interface IStaticPrefixProxyTerminalProviderOptions extends IPrefixProxyTerminalProviderOptionsBase {\n /**\n * The prefix that should be added to each line of output.\n */\n prefix: string;\n}\n\n/**\n * Options for {@link PrefixProxyTerminalProvider}.\n *\n * @beta\n */\nexport interface IDynamicPrefixProxyTerminalProviderOptions extends IPrefixProxyTerminalProviderOptionsBase {\n /**\n * A function that returns the prefix that should be added to each line of output. This is useful\n * for prefixing each line with a timestamp.\n */\n getPrefix: () => string;\n}\n\n/**\n * @beta\n */\nexport type IPrefixProxyTerminalProviderOptions =\n | IStaticPrefixProxyTerminalProviderOptions\n | IDynamicPrefixProxyTerminalProviderOptions;\n\n/**\n * Wraps an existing {@link ITerminalProvider} that prefixes each line of output with a specified\n * prefix string.\n *\n * @beta\n */\nexport class PrefixProxyTerminalProvider implements ITerminalProvider {\n private readonly _parentTerminalProvider: ITerminalProvider;\n private readonly _getPrefix: () => string;\n private readonly _newlineRegex: RegExp;\n private _isOnNewline: boolean;\n\n public constructor(options: IPrefixProxyTerminalProviderOptions) {\n const { terminalProvider } = options;\n\n this._parentTerminalProvider = terminalProvider;\n\n if ((options as IStaticPrefixProxyTerminalProviderOptions).prefix !== undefined) {\n const { prefix } = options as IStaticPrefixProxyTerminalProviderOptions;\n this._getPrefix = () => prefix;\n } else {\n const { getPrefix } = options as IDynamicPrefixProxyTerminalProviderOptions;\n this._getPrefix = getPrefix;\n }\n\n this._isOnNewline = true;\n\n this._newlineRegex = new RegExp(`${Text.escapeRegExp(terminalProvider.eolCharacter)}|\\\\n`, 'g');\n }\n\n /** @override */\n public get supportsColor(): boolean {\n return this._parentTerminalProvider.supportsColor;\n }\n\n /** @override */\n public get eolCharacter(): string {\n return this._parentTerminalProvider.eolCharacter;\n }\n\n /** @override */\n public write(data: string, severity: TerminalProviderSeverity): void {\n // We need to track newlines to ensure that the prefix is added to each line\n let currentIndex: number = 0;\n let newlineMatch: RegExpExecArray | null;\n\n while ((newlineMatch = this._newlineRegex.exec(data))) {\n // Extract the line, add the prefix, and write it out with the newline\n const newlineIndex: number = newlineMatch.index;\n const newIndex: number = newlineIndex + newlineMatch[0].length;\n const prefix: string = this._isOnNewline ? this._getPrefix() : '';\n const dataToWrite: string = `${prefix}${data.substring(currentIndex, newIndex)}`;\n this._parentTerminalProvider.write(dataToWrite, severity);\n // Update the currentIndex to start the search from the char after the newline\n currentIndex = newIndex;\n this._isOnNewline = true;\n }\n\n // The remaining data is not postfixed by a newline, so write out the data and set _isNewline to false\n const remainingData: string = data.substring(currentIndex);\n if (remainingData.length) {\n const prefix: string = this._isOnNewline ? this._getPrefix() : '';\n this._parentTerminalProvider.write(`${prefix}${remainingData}`, severity);\n this._isOnNewline = false;\n }\n }\n}\n"]}
@@ -0,0 +1,146 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2
+ // See LICENSE in the project root for license information.
3
+ import { Text } from '@rushstack/node-core-library';
4
+ /**
5
+ * A sensible fallback column width for consoles.
6
+ *
7
+ * @public
8
+ */
9
+ export const DEFAULT_CONSOLE_WIDTH = 80;
10
+ /**
11
+ * A collection of utilities for printing messages to the console.
12
+ *
13
+ * @public
14
+ */
15
+ export class PrintUtilities {
16
+ /**
17
+ * Returns the width of the console, measured in columns
18
+ */
19
+ static getConsoleWidth() {
20
+ var _a;
21
+ return (_a = process.stdout) === null || _a === void 0 ? void 0 : _a.columns;
22
+ }
23
+ static wrapWords(text, maxLineLength, indentOrLinePrefix) {
24
+ const wrappedLines = PrintUtilities.wrapWordsToLines(text, maxLineLength, indentOrLinePrefix // TS is confused by the overloads
25
+ );
26
+ return wrappedLines.join('\n');
27
+ }
28
+ static wrapWordsToLines(text, maxLineLength, indentOrLinePrefix) {
29
+ var _a;
30
+ let linePrefix;
31
+ switch (typeof indentOrLinePrefix) {
32
+ case 'number':
33
+ linePrefix = ' '.repeat(indentOrLinePrefix);
34
+ break;
35
+ case 'string':
36
+ linePrefix = indentOrLinePrefix;
37
+ break;
38
+ default:
39
+ linePrefix = '';
40
+ break;
41
+ }
42
+ const linePrefixLength = linePrefix.length;
43
+ if (!maxLineLength) {
44
+ maxLineLength = PrintUtilities.getConsoleWidth() || DEFAULT_CONSOLE_WIDTH;
45
+ }
46
+ // Apply word wrapping and the provided line prefix, while also respecting existing newlines
47
+ // and prefix spaces that may exist in the text string already.
48
+ const lines = Text.splitByNewLines(text);
49
+ const wrappedLines = [];
50
+ for (const line of lines) {
51
+ if (line.length + linePrefixLength <= maxLineLength) {
52
+ wrappedLines.push(linePrefix + line);
53
+ }
54
+ else {
55
+ const lineAdditionalPrefix = ((_a = line.match(/^\s*/)) === null || _a === void 0 ? void 0 : _a[0]) || '';
56
+ const whitespaceRegexp = /\s+/g;
57
+ let currentWhitespaceMatch = null;
58
+ let previousWhitespaceMatch;
59
+ let currentLineStartIndex = lineAdditionalPrefix.length;
60
+ let previousBreakRanOver = false;
61
+ while ((currentWhitespaceMatch = whitespaceRegexp.exec(line)) !== null) {
62
+ if (currentWhitespaceMatch.index + linePrefixLength - currentLineStartIndex > maxLineLength) {
63
+ let whitespaceToSplitAt;
64
+ if (!previousWhitespaceMatch ||
65
+ // Handle the case where there are two words longer than the maxLineLength in a row
66
+ previousBreakRanOver) {
67
+ whitespaceToSplitAt = currentWhitespaceMatch;
68
+ }
69
+ else {
70
+ whitespaceToSplitAt = previousWhitespaceMatch;
71
+ }
72
+ wrappedLines.push(linePrefix +
73
+ lineAdditionalPrefix +
74
+ line.substring(currentLineStartIndex, whitespaceToSplitAt.index));
75
+ previousBreakRanOver = whitespaceToSplitAt.index - currentLineStartIndex > maxLineLength;
76
+ currentLineStartIndex = whitespaceToSplitAt.index + whitespaceToSplitAt[0].length;
77
+ }
78
+ else {
79
+ previousBreakRanOver = false;
80
+ }
81
+ previousWhitespaceMatch = currentWhitespaceMatch;
82
+ }
83
+ if (previousWhitespaceMatch &&
84
+ line.length + linePrefixLength - currentLineStartIndex > maxLineLength) {
85
+ const whitespaceToSplitAt = previousWhitespaceMatch;
86
+ wrappedLines.push(linePrefix +
87
+ lineAdditionalPrefix +
88
+ line.substring(currentLineStartIndex, whitespaceToSplitAt.index));
89
+ currentLineStartIndex = whitespaceToSplitAt.index + whitespaceToSplitAt[0].length;
90
+ }
91
+ if (currentLineStartIndex < line.length) {
92
+ wrappedLines.push(linePrefix + lineAdditionalPrefix + line.substring(currentLineStartIndex));
93
+ }
94
+ }
95
+ }
96
+ return wrappedLines;
97
+ }
98
+ /**
99
+ * Displays a message in the console wrapped in a box UI.
100
+ *
101
+ * @param message - The message to display.
102
+ * @param terminal - The terminal to write the message to.
103
+ * @param boxWidth - The width of the box, defaults to half of the console width.
104
+ */
105
+ static printMessageInBox(message, terminal, boxWidth) {
106
+ if (!boxWidth) {
107
+ const consoleWidth = PrintUtilities.getConsoleWidth() || DEFAULT_CONSOLE_WIDTH;
108
+ boxWidth = Math.floor(consoleWidth / 2);
109
+ }
110
+ const maxLineLength = boxWidth - 10;
111
+ const wrappedMessageLines = PrintUtilities.wrapWordsToLines(message, maxLineLength);
112
+ let longestLineLength = 0;
113
+ const trimmedLines = [];
114
+ for (const line of wrappedMessageLines) {
115
+ const trimmedLine = line.trim();
116
+ trimmedLines.push(trimmedLine);
117
+ longestLineLength = Math.max(longestLineLength, trimmedLine.length);
118
+ }
119
+ if (longestLineLength > boxWidth - 2) {
120
+ // If the longest line is longer than the box, print bars above and below the message
121
+ // ═════════════
122
+ // Message
123
+ // ═════════════
124
+ const headerAndFooter = ` ${'═'.repeat(boxWidth)}`;
125
+ terminal.writeLine(headerAndFooter);
126
+ for (const line of wrappedMessageLines) {
127
+ terminal.writeLine(` ${line}`);
128
+ }
129
+ terminal.writeLine(headerAndFooter);
130
+ }
131
+ else {
132
+ // ╔═══════════╗
133
+ // ║ Message ║
134
+ // ╚═══════════╝
135
+ terminal.writeLine(` ╔${'═'.repeat(boxWidth - 2)}╗`);
136
+ for (const trimmedLine of trimmedLines) {
137
+ const padding = boxWidth - trimmedLine.length - 2;
138
+ const leftPadding = Math.floor(padding / 2);
139
+ const rightPadding = padding - leftPadding;
140
+ terminal.writeLine(` ║${' '.repeat(leftPadding)}${trimmedLine}${' '.repeat(rightPadding)}║`);
141
+ }
142
+ terminal.writeLine(` ╚${'═'.repeat(boxWidth - 2)}╝`);
143
+ }
144
+ }
145
+ }
146
+ //# sourceMappingURL=PrintUtilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrintUtilities.js","sourceRoot":"","sources":["../src/PrintUtilities.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { Text } from '@rushstack/node-core-library';\n\nimport type { ITerminal } from './ITerminal';\n\n/**\n * A sensible fallback column width for consoles.\n *\n * @public\n */\nexport const DEFAULT_CONSOLE_WIDTH: number = 80;\n\n/**\n * A collection of utilities for printing messages to the console.\n *\n * @public\n */\nexport class PrintUtilities {\n /**\n * Returns the width of the console, measured in columns\n */\n public static getConsoleWidth(): number | undefined {\n return process.stdout?.columns;\n }\n\n /**\n * Applies word wrapping.\n *\n * @param text - The text to wrap\n * @param maxLineLength - The maximum length of a line, defaults to the console width\n * @param indent - The number of spaces to indent the wrapped lines, defaults to 0\n */\n public static wrapWords(text: string, maxLineLength?: number, indent?: number): string;\n /**\n * Applies word wrapping.\n *\n * @param text - The text to wrap\n * @param maxLineLength - The maximum length of a line, defaults to the console width\n * @param linePrefix - The string to prefix each line with, defaults to ''\n */\n public static wrapWords(text: string, maxLineLength?: number, linePrefix?: string): string;\n /**\n * Applies word wrapping.\n *\n * @param text - The text to wrap\n * @param maxLineLength - The maximum length of a line, defaults to the console width\n * @param indentOrLinePrefix - The number of spaces to indent the wrapped lines or the string to prefix\n * each line with, defaults to no prefix\n */\n public static wrapWords(text: string, maxLineLength?: number, indentOrLinePrefix?: number | string): string;\n public static wrapWords(\n text: string,\n maxLineLength?: number,\n indentOrLinePrefix?: number | string\n ): string {\n const wrappedLines: string[] = PrintUtilities.wrapWordsToLines(\n text,\n maxLineLength,\n indentOrLinePrefix as string | undefined // TS is confused by the overloads\n );\n return wrappedLines.join('\\n');\n }\n\n /**\n * Applies word wrapping and returns an array of lines.\n *\n * @param text - The text to wrap\n * @param maxLineLength - The maximum length of a line, defaults to the console width\n * @param indent - The number of spaces to indent the wrapped lines, defaults to 0\n */\n public static wrapWordsToLines(text: string, maxLineLength?: number, indent?: number): string[];\n /**\n * Applies word wrapping and returns an array of lines.\n *\n * @param text - The text to wrap\n * @param maxLineLength - The maximum length of a line, defaults to the console width\n * @param linePrefix - The string to prefix each line with, defaults to ''\n */\n public static wrapWordsToLines(text: string, maxLineLength?: number, linePrefix?: string): string[];\n /**\n * Applies word wrapping and returns an array of lines.\n *\n * @param text - The text to wrap\n * @param maxLineLength - The maximum length of a line, defaults to the console width\n * @param indentOrLinePrefix - The number of spaces to indent the wrapped lines or the string to prefix\n * each line with, defaults to no prefix\n */\n public static wrapWordsToLines(\n text: string,\n maxLineLength?: number,\n indentOrLinePrefix?: number | string\n ): string[];\n public static wrapWordsToLines(\n text: string,\n maxLineLength?: number,\n indentOrLinePrefix?: number | string\n ): string[] {\n let linePrefix: string;\n switch (typeof indentOrLinePrefix) {\n case 'number':\n linePrefix = ' '.repeat(indentOrLinePrefix);\n break;\n case 'string':\n linePrefix = indentOrLinePrefix;\n break;\n default:\n linePrefix = '';\n break;\n }\n\n const linePrefixLength: number = linePrefix.length;\n\n if (!maxLineLength) {\n maxLineLength = PrintUtilities.getConsoleWidth() || DEFAULT_CONSOLE_WIDTH;\n }\n\n // Apply word wrapping and the provided line prefix, while also respecting existing newlines\n // and prefix spaces that may exist in the text string already.\n const lines: string[] = Text.splitByNewLines(text);\n\n const wrappedLines: string[] = [];\n for (const line of lines) {\n if (line.length + linePrefixLength <= maxLineLength) {\n wrappedLines.push(linePrefix + line);\n } else {\n const lineAdditionalPrefix: string = line.match(/^\\s*/)?.[0] || '';\n const whitespaceRegexp: RegExp = /\\s+/g;\n let currentWhitespaceMatch: RegExpExecArray | null = null;\n let previousWhitespaceMatch: RegExpExecArray | undefined;\n let currentLineStartIndex: number = lineAdditionalPrefix.length;\n let previousBreakRanOver: boolean = false;\n while ((currentWhitespaceMatch = whitespaceRegexp.exec(line)) !== null) {\n if (currentWhitespaceMatch.index + linePrefixLength - currentLineStartIndex > maxLineLength) {\n let whitespaceToSplitAt: RegExpExecArray | undefined;\n if (\n !previousWhitespaceMatch ||\n // Handle the case where there are two words longer than the maxLineLength in a row\n previousBreakRanOver\n ) {\n whitespaceToSplitAt = currentWhitespaceMatch;\n } else {\n whitespaceToSplitAt = previousWhitespaceMatch;\n }\n\n wrappedLines.push(\n linePrefix +\n lineAdditionalPrefix +\n line.substring(currentLineStartIndex, whitespaceToSplitAt.index)\n );\n previousBreakRanOver = whitespaceToSplitAt.index - currentLineStartIndex > maxLineLength;\n currentLineStartIndex = whitespaceToSplitAt.index + whitespaceToSplitAt[0].length;\n } else {\n previousBreakRanOver = false;\n }\n\n previousWhitespaceMatch = currentWhitespaceMatch;\n }\n\n if (\n previousWhitespaceMatch &&\n line.length + linePrefixLength - currentLineStartIndex > maxLineLength\n ) {\n const whitespaceToSplitAt: RegExpExecArray = previousWhitespaceMatch;\n\n wrappedLines.push(\n linePrefix +\n lineAdditionalPrefix +\n line.substring(currentLineStartIndex, whitespaceToSplitAt.index)\n );\n currentLineStartIndex = whitespaceToSplitAt.index + whitespaceToSplitAt[0].length;\n }\n\n if (currentLineStartIndex < line.length) {\n wrappedLines.push(linePrefix + lineAdditionalPrefix + line.substring(currentLineStartIndex));\n }\n }\n }\n\n return wrappedLines;\n }\n\n /**\n * Displays a message in the console wrapped in a box UI.\n *\n * @param message - The message to display.\n * @param terminal - The terminal to write the message to.\n * @param boxWidth - The width of the box, defaults to half of the console width.\n */\n public static printMessageInBox(message: string, terminal: ITerminal, boxWidth?: number): void {\n if (!boxWidth) {\n const consoleWidth: number = PrintUtilities.getConsoleWidth() || DEFAULT_CONSOLE_WIDTH;\n boxWidth = Math.floor(consoleWidth / 2);\n }\n\n const maxLineLength: number = boxWidth - 10;\n const wrappedMessageLines: string[] = PrintUtilities.wrapWordsToLines(message, maxLineLength);\n let longestLineLength: number = 0;\n const trimmedLines: string[] = [];\n for (const line of wrappedMessageLines) {\n const trimmedLine: string = line.trim();\n trimmedLines.push(trimmedLine);\n longestLineLength = Math.max(longestLineLength, trimmedLine.length);\n }\n\n if (longestLineLength > boxWidth - 2) {\n // If the longest line is longer than the box, print bars above and below the message\n // ═════════════\n // Message\n // ═════════════\n const headerAndFooter: string = ` ${'═'.repeat(boxWidth)}`;\n terminal.writeLine(headerAndFooter);\n for (const line of wrappedMessageLines) {\n terminal.writeLine(` ${line}`);\n }\n\n terminal.writeLine(headerAndFooter);\n } else {\n // ╔═══════════╗\n // ║ Message ║\n // ╚═══════════╝\n terminal.writeLine(` ╔${'═'.repeat(boxWidth - 2)}╗`);\n for (const trimmedLine of trimmedLines) {\n const padding: number = boxWidth - trimmedLine.length - 2;\n const leftPadding: number = Math.floor(padding / 2);\n const rightPadding: number = padding - leftPadding;\n terminal.writeLine(` ║${' '.repeat(leftPadding)}${trimmedLine}${' '.repeat(rightPadding)}║`);\n }\n terminal.writeLine(` ╚${'═'.repeat(boxWidth - 2)}╝`);\n }\n }\n}\n"]}
@@ -0,0 +1,85 @@
1
+ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2
+ // See LICENSE in the project root for license information.
3
+ import { parseProblemMatchersJson } from '@rushstack/problem-matcher';
4
+ import { TerminalWritable } from './TerminalWritable';
5
+ /**
6
+ * A {@link TerminalWritable} that consumes line-oriented terminal output and extracts structured
7
+ * problems using one or more {@link @rushstack/problem-matcher#IProblemMatcher | IProblemMatcher} instances.
8
+ *
9
+ * @remarks
10
+ * This collector expects that each incoming {@link ITerminalChunk} represents a single line terminated
11
+ * by a `"\n"` character (for example when preceded by {@link StderrLineTransform} / `StdioLineTransform`).
12
+ * If a chunk does not end with a newline an error is thrown to surface incorrect pipeline wiring early.
13
+ *
14
+ * @beta
15
+ */
16
+ export class ProblemCollector extends TerminalWritable {
17
+ constructor(options) {
18
+ super(options);
19
+ this._problems = new Set();
20
+ if (!options ||
21
+ ((!options.matchers || options.matchers.length === 0) &&
22
+ (!options.matcherJson || options.matcherJson.length === 0))) {
23
+ throw new Error('ProblemCollector requires at least one problem matcher.');
24
+ }
25
+ const fromJson = options.matcherJson
26
+ ? parseProblemMatchersJson(options.matcherJson)
27
+ : [];
28
+ this._matchers = [...(options.matchers || []), ...fromJson];
29
+ if (this._matchers.length === 0) {
30
+ throw new Error('ProblemCollector requires at least one problem matcher.');
31
+ }
32
+ this._onProblem = options.onProblem;
33
+ }
34
+ /**
35
+ * {@inheritdoc IProblemCollector}
36
+ */
37
+ get problems() {
38
+ return this._problems;
39
+ }
40
+ /**
41
+ * {@inheritdoc TerminalWritable}
42
+ */
43
+ onWriteChunk(chunk) {
44
+ var _a;
45
+ const text = chunk.text;
46
+ if (text.length === 0 || text[text.length - 1] !== '\n') {
47
+ throw new Error('ProblemCollector expects chunks that were split into newline terminated lines. ' +
48
+ 'Invalid input: ' +
49
+ JSON.stringify(text));
50
+ }
51
+ for (const matcher of this._matchers) {
52
+ const problem = matcher.exec(text);
53
+ if (problem) {
54
+ const finalized = {
55
+ ...problem,
56
+ matcherName: matcher.name
57
+ };
58
+ this._problems.add(finalized);
59
+ (_a = this._onProblem) === null || _a === void 0 ? void 0 : _a.call(this, finalized);
60
+ }
61
+ }
62
+ }
63
+ /**
64
+ * {@inheritdoc TerminalWritable}
65
+ */
66
+ onClose() {
67
+ var _a;
68
+ for (const matcher of this._matchers) {
69
+ if (matcher.flush) {
70
+ const flushed = matcher.flush();
71
+ if (flushed && flushed.length > 0) {
72
+ for (const problem of flushed) {
73
+ const finalized = {
74
+ ...problem,
75
+ matcherName: matcher.name
76
+ };
77
+ this._problems.add(finalized);
78
+ (_a = this._onProblem) === null || _a === void 0 ? void 0 : _a.call(this, finalized);
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ }
85
+ //# sourceMappingURL=ProblemCollector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProblemCollector.js","sourceRoot":"","sources":["../src/ProblemCollector.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { parseProblemMatchersJson } from '@rushstack/problem-matcher';\nimport type { IProblemMatcher, IProblemMatcherJson, IProblem } from '@rushstack/problem-matcher';\n\nimport type { ITerminalChunk } from './ITerminalChunk';\nimport { type ITerminalWritableOptions, TerminalWritable } from './TerminalWritable';\nimport type { IProblemCollector } from './IProblemCollector';\n\n/**\n * Constructor options for {@link ProblemCollector}.\n * @beta\n */\nexport interface IProblemCollectorOptions extends ITerminalWritableOptions {\n /**\n * The set of matchers that will be applied to each incoming line. Must contain at least one item.\n */\n matchers?: IProblemMatcher[];\n /**\n * VS Code style problem matcher definitions. These will be converted to\n * {@link @rushstack/problem-matcher#IProblemMatcher | IProblemMatcher} definitions.\n */\n matcherJson?: IProblemMatcherJson[];\n /**\n * Optional callback invoked immediately whenever a problem is produced.\n */\n onProblem?: (problem: IProblem) => void;\n}\n\n/**\n * A {@link TerminalWritable} that consumes line-oriented terminal output and extracts structured\n * problems using one or more {@link @rushstack/problem-matcher#IProblemMatcher | IProblemMatcher} instances.\n *\n * @remarks\n * This collector expects that each incoming {@link ITerminalChunk} represents a single line terminated\n * by a `\"\\n\"` character (for example when preceded by {@link StderrLineTransform} / `StdioLineTransform`).\n * If a chunk does not end with a newline an error is thrown to surface incorrect pipeline wiring early.\n *\n * @beta\n */\nexport class ProblemCollector extends TerminalWritable implements IProblemCollector {\n private readonly _matchers: IProblemMatcher[];\n private readonly _problems: Set<IProblem> = new Set();\n private readonly _onProblem: ((problem: IProblem) => void) | undefined;\n\n public constructor(options: IProblemCollectorOptions) {\n super(options);\n\n if (\n !options ||\n ((!options.matchers || options.matchers.length === 0) &&\n (!options.matcherJson || options.matcherJson.length === 0))\n ) {\n throw new Error('ProblemCollector requires at least one problem matcher.');\n }\n\n const fromJson: IProblemMatcher[] = options.matcherJson\n ? parseProblemMatchersJson(options.matcherJson)\n : [];\n this._matchers = [...(options.matchers || []), ...fromJson];\n if (this._matchers.length === 0) {\n throw new Error('ProblemCollector requires at least one problem matcher.');\n }\n this._onProblem = options.onProblem;\n }\n\n /**\n * {@inheritdoc IProblemCollector}\n */\n public get problems(): ReadonlySet<IProblem> {\n return this._problems;\n }\n\n /**\n * {@inheritdoc TerminalWritable}\n */\n protected onWriteChunk(chunk: ITerminalChunk): void {\n const text: string = chunk.text;\n if (text.length === 0 || text[text.length - 1] !== '\\n') {\n throw new Error(\n 'ProblemCollector expects chunks that were split into newline terminated lines. ' +\n 'Invalid input: ' +\n JSON.stringify(text)\n );\n }\n\n for (const matcher of this._matchers) {\n const problem: IProblem | false = matcher.exec(text);\n if (problem) {\n const finalized: IProblem = {\n ...problem,\n matcherName: matcher.name\n };\n this._problems.add(finalized);\n this._onProblem?.(finalized);\n }\n }\n }\n\n /**\n * {@inheritdoc TerminalWritable}\n */\n protected onClose(): void {\n for (const matcher of this._matchers) {\n if (matcher.flush) {\n const flushed: IProblem[] = matcher.flush();\n if (flushed && flushed.length > 0) {\n for (const problem of flushed) {\n const finalized: IProblem = {\n ...problem,\n matcherName: matcher.name\n };\n this._problems.add(finalized);\n this._onProblem?.(finalized);\n }\n }\n }\n }\n }\n}\n"]}