@socketsecurity/lib 1.0.4 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/abort.js.map +2 -2
- package/dist/argv/parse.js.map +2 -2
- package/dist/arrays.d.ts +143 -0
- package/dist/arrays.js.map +2 -2
- package/dist/bin.js +1 -4
- package/dist/bin.js.map +2 -2
- package/dist/cacache.d.ts +0 -2
- package/dist/cacache.js +0 -1
- package/dist/cacache.js.map +2 -2
- package/dist/cache-with-ttl.js.map +2 -2
- package/dist/dlx.js.map +2 -2
- package/dist/external/@yarnpkg/extensions.d.ts +0 -1
- package/dist/external/cacache.d.ts +0 -7
- package/dist/external/debug.d.ts +0 -3
- package/dist/external/fast-sort.d.ts +0 -1
- package/dist/external/libnpmpack.d.ts +0 -1
- package/dist/external/make-fetch-happen.d.ts +0 -1
- package/dist/external/pacote.d.ts +0 -5
- package/dist/external/semver.d.ts +0 -1
- package/dist/external/validate-npm-package-name.js +1 -1
- package/dist/external/yargs-parser.d.ts +0 -1
- package/dist/external/yoctocolors-cjs.js +1 -1
- package/dist/external/zod.js +9 -9
- package/dist/fs.d.ts +595 -23
- package/dist/fs.js.map +2 -2
- package/dist/git.d.ts +488 -41
- package/dist/git.js.map +2 -2
- package/dist/github.d.ts +361 -12
- package/dist/github.js.map +2 -2
- package/dist/http-request.d.ts +463 -4
- package/dist/http-request.js.map +2 -2
- package/dist/json.d.ts +177 -4
- package/dist/json.js.map +2 -2
- package/dist/logger.d.ts +823 -70
- package/dist/logger.js +654 -51
- package/dist/logger.js.map +2 -2
- package/dist/objects.d.ts +386 -10
- package/dist/objects.js.map +2 -2
- package/dist/path.d.ts +270 -6
- package/dist/path.js.map +2 -2
- package/dist/promises.d.ts +432 -27
- package/dist/promises.js +3 -0
- package/dist/promises.js.map +2 -2
- package/dist/signal-exit.js.map +2 -2
- package/dist/sorts.js.map +2 -2
- package/dist/spawn.d.ts +242 -33
- package/dist/spawn.js.map +2 -2
- package/dist/spinner.d.ts +260 -20
- package/dist/spinner.js +201 -63
- package/dist/spinner.js.map +2 -2
- package/dist/stdio/clear.d.ts +130 -9
- package/dist/stdio/clear.js.map +2 -2
- package/dist/stdio/divider.d.ts +106 -10
- package/dist/stdio/divider.js +10 -0
- package/dist/stdio/divider.js.map +2 -2
- package/dist/stdio/footer.d.ts +70 -3
- package/dist/stdio/footer.js.map +2 -2
- package/dist/stdio/header.d.ts +93 -12
- package/dist/stdio/header.js.map +2 -2
- package/dist/stdio/mask.d.ts +82 -14
- package/dist/stdio/mask.js +25 -4
- package/dist/stdio/mask.js.map +2 -2
- package/dist/stdio/progress.d.ts +112 -15
- package/dist/stdio/progress.js +43 -3
- package/dist/stdio/progress.js.map +2 -2
- package/dist/stdio/prompts.d.ts +95 -5
- package/dist/stdio/prompts.js.map +2 -2
- package/dist/stdio/stderr.d.ts +114 -11
- package/dist/stdio/stderr.js.map +2 -2
- package/dist/stdio/stdout.d.ts +107 -11
- package/dist/stdio/stdout.js.map +2 -2
- package/dist/strings.d.ts +357 -28
- package/dist/strings.js.map +2 -2
- package/dist/suppress-warnings.js.map +2 -2
- package/dist/validation/json-parser.d.ts +226 -7
- package/dist/validation/json-parser.js.map +2 -2
- package/dist/validation/types.d.ts +114 -12
- package/dist/validation/types.js.map +1 -1
- package/package.json +5 -3
package/dist/stdio/divider.js
CHANGED
|
@@ -38,15 +38,25 @@ function printDivider(options) {
|
|
|
38
38
|
console.log(divider(options));
|
|
39
39
|
}
|
|
40
40
|
const dividers = {
|
|
41
|
+
/** Thick double-line divider using `═` */
|
|
41
42
|
thick: () => divider({ char: "\u2550" }),
|
|
43
|
+
/** Thin single-line divider using `─` */
|
|
42
44
|
thin: () => divider({ char: "\u2500" }),
|
|
45
|
+
/** Double-line divider (alias for thick) */
|
|
43
46
|
double: () => divider({ char: "\u2550" }),
|
|
47
|
+
/** Simple single dash divider using `-` */
|
|
44
48
|
single: () => divider({ char: "-" }),
|
|
49
|
+
/** Dotted divider using `·` */
|
|
45
50
|
dotted: () => divider({ char: "\xB7" }),
|
|
51
|
+
/** Dashed divider using `╌` */
|
|
46
52
|
dashed: () => divider({ char: "\u254C" }),
|
|
53
|
+
/** Wave divider using `~` */
|
|
47
54
|
wave: () => divider({ char: "~" }),
|
|
55
|
+
/** Star divider using `*` */
|
|
48
56
|
star: () => divider({ char: "*" }),
|
|
57
|
+
/** Diamond divider using `◆` */
|
|
49
58
|
diamond: () => divider({ char: "\u25C6" }),
|
|
59
|
+
/** Arrow divider using `→` */
|
|
50
60
|
arrow: () => divider({ char: "\u2192" })
|
|
51
61
|
};
|
|
52
62
|
function printThickDivider() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/stdio/divider.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @fileoverview Console divider and separator utilities.\n * Provides various line styles for visual separation in CLI output.\n */\n\nimport { repeatString } from '../strings'\n\nexport interface DividerOptions {\n width?: number\n char?: string\n color?: (text: string) => string\n}\n\n/**\n * Create a divider line with custom character and width.\n */\nexport function divider(options?: DividerOptions): string {\n const opts = { __proto__: null, ...options } as DividerOptions\n const { char = '\u2550', width = 55 } = opts\n return repeatString(char, width)\n}\n\n/**\n * Print a divider line to console.\n */\nexport function printDivider(options?: DividerOptions): void {\n console.log(divider(options))\n}\n\n/**\n * Common divider presets.\n */\nexport const dividers = {\n thick: () => divider({ char: '\u2550' }),\n thin: () => divider({ char: '\u2500' }),\n double: () => divider({ char: '\u2550' }),\n single: () => divider({ char: '-' }),\n dotted: () => divider({ char: '\u00B7' }),\n dashed: () => divider({ char: '\u254C' }),\n wave: () => divider({ char: '~' }),\n star: () => divider({ char: '*' }),\n diamond: () => divider({ char: '\u25C6' }),\n arrow: () => divider({ char: '\u2192' }),\n} as const\n\n/**\n * Print a thick divider (default).\n */\nexport function printThickDivider(): void {\n printDivider({ char: '\u2550' })\n}\n\n/**\n * Print a thin divider.\n */\nexport function printThinDivider(): void {\n printDivider({ char: '\u2500' })\n}\n\n/**\n * Print a dotted line
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,qBAA6B;
|
|
4
|
+
"sourcesContent": ["/**\n * @fileoverview Console divider and separator utilities.\n * Provides various line styles for visual separation in CLI output.\n */\n\nimport { repeatString } from '../strings'\n\nexport interface DividerOptions {\n /**\n * Width of the divider line in characters.\n * @default 55\n */\n width?: number | undefined\n /**\n * Character to repeat for the divider line.\n * @default '\u2550'\n */\n char?: string | undefined\n /**\n * Optional color function to apply to the divider.\n * Accepts a function from `yoctocolors` or similar.\n */\n color?: ((text: string) => string) | undefined\n}\n\n/**\n * Create a divider line with custom character and width.\n * Returns a string of repeated characters for visual separation.\n *\n * @param options - Divider formatting options\n * @returns Divider string\n *\n * @example\n * ```ts\n * console.log(divider()) // Default: 55 '\u2550' characters\n * console.log(divider({ char: '-', width: 40 }))\n * console.log(divider({ char: '\u00B7', width: 30 }))\n * ```\n */\nexport function divider(options?: DividerOptions): string {\n const opts = { __proto__: null, ...options } as DividerOptions\n const { char = '\u2550', width = 55 } = opts\n return repeatString(char, width)\n}\n\n/**\n * Print a divider line directly to console.\n *\n * @param options - Divider formatting options\n *\n * @example\n * ```ts\n * printDivider() // Prints default divider\n * printDivider({ char: '\u2500', width: 60 })\n * ```\n */\nexport function printDivider(options?: DividerOptions): void {\n console.log(divider(options))\n}\n\n/**\n * Common divider style presets.\n * Provides quick access to popular divider styles.\n *\n * @example\n * ```ts\n * console.log(dividers.thick()) // \u2550\u2550\u2550\u2550\u2550\u2550\u2550...\n * console.log(dividers.thin()) // \u2500\u2500\u2500\u2500\u2500\u2500\u2500...\n * console.log(dividers.dotted()) // \u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7...\n * ```\n */\nexport const dividers = {\n /** Thick double-line divider using `\u2550` */\n thick: () => divider({ char: '\u2550' }),\n /** Thin single-line divider using `\u2500` */\n thin: () => divider({ char: '\u2500' }),\n /** Double-line divider (alias for thick) */\n double: () => divider({ char: '\u2550' }),\n /** Simple single dash divider using `-` */\n single: () => divider({ char: '-' }),\n /** Dotted divider using `\u00B7` */\n dotted: () => divider({ char: '\u00B7' }),\n /** Dashed divider using `\u254C` */\n dashed: () => divider({ char: '\u254C' }),\n /** Wave divider using `~` */\n wave: () => divider({ char: '~' }),\n /** Star divider using `*` */\n star: () => divider({ char: '*' }),\n /** Diamond divider using `\u25C6` */\n diamond: () => divider({ char: '\u25C6' }),\n /** Arrow divider using `\u2192` */\n arrow: () => divider({ char: '\u2192' }),\n} as const\n\n/**\n * Print a thick divider line (default style).\n * Convenience function using `\u2550` character.\n *\n * @example\n * ```ts\n * printThickDivider()\n * // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n * ```\n */\nexport function printThickDivider(): void {\n printDivider({ char: '\u2550' })\n}\n\n/**\n * Print a thin divider line.\n * Convenience function using `\u2500` character.\n *\n * @example\n * ```ts\n * printThinDivider()\n * // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * ```\n */\nexport function printThinDivider(): void {\n printDivider({ char: '\u2500' })\n}\n\n/**\n * Print a dotted divider line.\n * Convenience function using `\u00B7` character.\n *\n * @example\n * ```ts\n * printDottedDivider()\n * // \u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\u00B7\n * ```\n */\nexport function printDottedDivider(): void {\n printDivider({ char: '\u00B7' })\n}\n\n/**\n * Create a section break with blank lines before and after the divider.\n * Useful for creating visual separation between major sections.\n *\n * @param options - Divider formatting options\n * @returns Section break string with newlines\n *\n * @example\n * ```ts\n * console.log('Previous section')\n * console.log(sectionBreak())\n * console.log('Next section')\n * // Output:\n * // Previous section\n * //\n * // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n * //\n * // Next section\n * ```\n */\nexport function sectionBreak(options?: DividerOptions): string {\n const div = divider(options)\n return `\\n${div}\\n`\n}\n\n/**\n * Print a section break with spacing directly to console.\n *\n * @param options - Divider formatting options\n *\n * @example\n * ```ts\n * console.log('Previous section')\n * printSectionBreak()\n * console.log('Next section')\n * ```\n */\nexport function printSectionBreak(options?: DividerOptions): void {\n console.log(sectionBreak(options))\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,qBAA6B;AAkCtB,SAAS,QAAQ,SAAkC;AACxD,QAAM,OAAO,EAAE,WAAW,MAAM,GAAG,QAAQ;AAC3C,QAAM,EAAE,OAAO,UAAK,QAAQ,GAAG,IAAI;AACnC,aAAO,6BAAa,MAAM,KAAK;AACjC;AAaO,SAAS,aAAa,SAAgC;AAC3D,UAAQ,IAAI,QAAQ,OAAO,CAAC;AAC9B;AAaO,MAAM,WAAW;AAAA;AAAA,EAEtB,OAAO,MAAM,QAAQ,EAAE,MAAM,SAAI,CAAC;AAAA;AAAA,EAElC,MAAM,MAAM,QAAQ,EAAE,MAAM,SAAI,CAAC;AAAA;AAAA,EAEjC,QAAQ,MAAM,QAAQ,EAAE,MAAM,SAAI,CAAC;AAAA;AAAA,EAEnC,QAAQ,MAAM,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA;AAAA,EAEnC,QAAQ,MAAM,QAAQ,EAAE,MAAM,OAAI,CAAC;AAAA;AAAA,EAEnC,QAAQ,MAAM,QAAQ,EAAE,MAAM,SAAI,CAAC;AAAA;AAAA,EAEnC,MAAM,MAAM,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA;AAAA,EAEjC,MAAM,MAAM,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA;AAAA,EAEjC,SAAS,MAAM,QAAQ,EAAE,MAAM,SAAI,CAAC;AAAA;AAAA,EAEpC,OAAO,MAAM,QAAQ,EAAE,MAAM,SAAI,CAAC;AACpC;AAYO,SAAS,oBAA0B;AACxC,eAAa,EAAE,MAAM,SAAI,CAAC;AAC5B;AAYO,SAAS,mBAAyB;AACvC,eAAa,EAAE,MAAM,SAAI,CAAC;AAC5B;AAYO,SAAS,qBAA2B;AACzC,eAAa,EAAE,MAAM,OAAI,CAAC;AAC5B;AAsBO,SAAS,aAAa,SAAkC;AAC7D,QAAM,MAAM,QAAQ,OAAO;AAC3B,SAAO;AAAA,EAAK,GAAG;AAAA;AACjB;AAcO,SAAS,kBAAkB,SAAgC;AAChE,UAAQ,IAAI,aAAa,OAAO,CAAC;AACnC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/stdio/footer.d.ts
CHANGED
|
@@ -1,25 +1,92 @@
|
|
|
1
1
|
export interface FooterOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Width of the footer border in characters.
|
|
4
|
+
* @default 80
|
|
5
|
+
*/
|
|
2
6
|
width?: number | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Character to use for the border line.
|
|
9
|
+
* @default '='
|
|
10
|
+
*/
|
|
3
11
|
borderChar?: string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Include ISO timestamp in footer.
|
|
14
|
+
* @default false
|
|
15
|
+
*/
|
|
4
16
|
showTimestamp?: boolean | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Show duration since start time.
|
|
19
|
+
* @default false
|
|
20
|
+
*/
|
|
5
21
|
showDuration?: boolean | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Start time in milliseconds (from Date.now()).
|
|
24
|
+
* Required when `showDuration` is true.
|
|
25
|
+
*/
|
|
6
26
|
startTime?: number | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Color to apply to the footer message.
|
|
29
|
+
* @default 'gray'
|
|
30
|
+
*/
|
|
7
31
|
color?: 'cyan' | 'green' | 'yellow' | 'blue' | 'magenta' | 'red' | 'gray' | undefined;
|
|
8
32
|
}
|
|
9
33
|
export interface SummaryStats {
|
|
34
|
+
/** Total number of items processed */
|
|
10
35
|
total?: number | undefined;
|
|
36
|
+
/** Number of successful items */
|
|
11
37
|
success?: number | undefined;
|
|
38
|
+
/** Number of failed items */
|
|
12
39
|
failed?: number | undefined;
|
|
40
|
+
/** Number of skipped items */
|
|
13
41
|
skipped?: number | undefined;
|
|
42
|
+
/** Number of warnings */
|
|
14
43
|
warnings?: number | undefined;
|
|
44
|
+
/** Number of errors */
|
|
15
45
|
errors?: number | undefined;
|
|
46
|
+
/** Duration in milliseconds (timestamp value, not elapsed time) */
|
|
16
47
|
duration?: number | undefined;
|
|
17
48
|
}
|
|
18
49
|
/**
|
|
19
|
-
* Create a formatted footer.
|
|
50
|
+
* Create a formatted footer with optional message, timestamp, and duration.
|
|
51
|
+
* Useful for marking the end of CLI output or showing completion status.
|
|
52
|
+
*
|
|
53
|
+
* @param message - Optional message to display in footer
|
|
54
|
+
* @param options - Footer formatting options
|
|
55
|
+
* @returns Formatted footer string with border and optional info
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* const startTime = Date.now()
|
|
60
|
+
* // ... do work
|
|
61
|
+
* console.log(createFooter('Build complete', {
|
|
62
|
+
* width: 60,
|
|
63
|
+
* color: 'green',
|
|
64
|
+
* showDuration: true,
|
|
65
|
+
* startTime
|
|
66
|
+
* }))
|
|
67
|
+
* ```
|
|
20
68
|
*/
|
|
21
|
-
export declare function createFooter(message?: string, options?: FooterOptions): string;
|
|
69
|
+
export declare function createFooter(message?: string | undefined, options?: FooterOptions): string;
|
|
22
70
|
/**
|
|
23
|
-
* Create a summary footer with statistics.
|
|
71
|
+
* Create a summary footer with statistics and colored status indicators.
|
|
72
|
+
* Automatically formats success/failure/warning counts with appropriate colors.
|
|
73
|
+
* Useful for test results, build summaries, or batch operation reports.
|
|
74
|
+
*
|
|
75
|
+
* @param stats - Statistics to display in the summary
|
|
76
|
+
* @param options - Footer formatting options
|
|
77
|
+
* @returns Formatted summary footer string with colored indicators
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* console.log(createSummaryFooter({
|
|
82
|
+
* total: 150,
|
|
83
|
+
* success: 145,
|
|
84
|
+
* failed: 3,
|
|
85
|
+
* skipped: 2,
|
|
86
|
+
* warnings: 5
|
|
87
|
+
* }))
|
|
88
|
+
* // Output: Total: 150 | ✓ 145 passed | ✗ 3 failed | ○ 2 skipped | ⚠ 5 warnings
|
|
89
|
+
* // ========================================
|
|
90
|
+
* ```
|
|
24
91
|
*/
|
|
25
92
|
export declare function createSummaryFooter(stats: SummaryStats, options?: FooterOptions): string;
|
package/dist/stdio/footer.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/stdio/footer.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Console footer/summary formatting utilities.\n * Provides consistent footer and summary formatting for CLI applications.\n */\n\nimport colors from '../external/yoctocolors-cjs'\nimport { repeatString } from '../strings'\n\nexport interface FooterOptions {\n width?: number | undefined\n borderChar?: string | undefined\n showTimestamp?: boolean | undefined\n showDuration?: boolean | undefined\n startTime?: number | undefined\n color?:\n | 'cyan'\n | 'green'\n | 'yellow'\n | 'blue'\n | 'magenta'\n | 'red'\n | 'gray'\n | undefined\n}\n\nexport interface SummaryStats {\n total?: number | undefined\n success?: number | undefined\n failed?: number | undefined\n skipped?: number | undefined\n warnings?: number | undefined\n errors?: number | undefined\n duration?: number | undefined\n}\n\n/**\n * Create a formatted footer.\n */\nexport function createFooter(\n message?: string,\n options?: FooterOptions,\n): string {\n const {\n borderChar = '=',\n color = 'gray',\n showDuration = false,\n showTimestamp = false,\n startTime,\n width = 80,\n } = { __proto__: null, ...options } as FooterOptions\n\n const border = repeatString(borderChar, width)\n const lines: string[] = []\n\n if (message) {\n const colorFn = color && colors[color] ? colors[color] : (s: string) => s\n lines.push(colorFn(message))\n }\n\n if (showTimestamp) {\n const timestamp = new Date().toISOString()\n lines.push(colors.gray(`Completed at: ${timestamp}`))\n }\n\n if (showDuration && startTime) {\n const duration = Date.now() - startTime\n const seconds = (duration / 1000).toFixed(2)\n lines.push(colors.gray(`Duration: ${seconds}s`))\n }\n\n lines.push(border)\n return lines.join('\\n')\n}\n\n/**\n * Create a summary footer with statistics.\n */\nexport function createSummaryFooter(\n stats: SummaryStats,\n options?: FooterOptions,\n): string {\n const parts: string[] = []\n\n if (stats.total !== undefined) {\n parts.push(`Total: ${stats.total}`)\n }\n\n if (stats.success !== undefined) {\n parts.push(colors.green(`\u2713 ${stats.success} passed`))\n }\n\n if (stats.failed !== undefined && stats.failed > 0) {\n parts.push(colors.red(`\u2717 ${stats.failed} failed`))\n }\n\n if (stats.skipped !== undefined && stats.skipped > 0) {\n parts.push(colors.yellow(`\u25CB ${stats.skipped} skipped`))\n }\n\n if (stats.warnings !== undefined && stats.warnings > 0) {\n parts.push(colors.yellow(`\u26A0 ${stats.warnings} warnings`))\n }\n\n if (stats.errors !== undefined && stats.errors > 0) {\n parts.push(colors.red(`\u2717 ${stats.errors} errors`))\n }\n\n const message = parts.join(' | ')\n return createFooter(message, {\n ...options,\n showDuration: stats.duration !== undefined,\n ...(stats.duration !== undefined && { startTime: stats.duration }),\n })\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,6BAAmB;AACnB,qBAA6B;
|
|
4
|
+
"sourcesContent": ["/**\n * @fileoverview Console footer/summary formatting utilities.\n * Provides consistent footer and summary formatting for CLI applications.\n */\n\nimport colors from '../external/yoctocolors-cjs'\nimport { repeatString } from '../strings'\n\nexport interface FooterOptions {\n /**\n * Width of the footer border in characters.\n * @default 80\n */\n width?: number | undefined\n /**\n * Character to use for the border line.\n * @default '='\n */\n borderChar?: string | undefined\n /**\n * Include ISO timestamp in footer.\n * @default false\n */\n showTimestamp?: boolean | undefined\n /**\n * Show duration since start time.\n * @default false\n */\n showDuration?: boolean | undefined\n /**\n * Start time in milliseconds (from Date.now()).\n * Required when `showDuration` is true.\n */\n startTime?: number | undefined\n /**\n * Color to apply to the footer message.\n * @default 'gray'\n */\n color?:\n | 'cyan'\n | 'green'\n | 'yellow'\n | 'blue'\n | 'magenta'\n | 'red'\n | 'gray'\n | undefined\n}\n\nexport interface SummaryStats {\n /** Total number of items processed */\n total?: number | undefined\n /** Number of successful items */\n success?: number | undefined\n /** Number of failed items */\n failed?: number | undefined\n /** Number of skipped items */\n skipped?: number | undefined\n /** Number of warnings */\n warnings?: number | undefined\n /** Number of errors */\n errors?: number | undefined\n /** Duration in milliseconds (timestamp value, not elapsed time) */\n duration?: number | undefined\n}\n\n/**\n * Create a formatted footer with optional message, timestamp, and duration.\n * Useful for marking the end of CLI output or showing completion status.\n *\n * @param message - Optional message to display in footer\n * @param options - Footer formatting options\n * @returns Formatted footer string with border and optional info\n *\n * @example\n * ```ts\n * const startTime = Date.now()\n * // ... do work\n * console.log(createFooter('Build complete', {\n * width: 60,\n * color: 'green',\n * showDuration: true,\n * startTime\n * }))\n * ```\n */\nexport function createFooter(\n message?: string | undefined,\n options?: FooterOptions,\n): string {\n const {\n borderChar = '=',\n color = 'gray',\n showDuration = false,\n showTimestamp = false,\n startTime,\n width = 80,\n } = { __proto__: null, ...options } as FooterOptions\n\n const border = repeatString(borderChar, width)\n const lines: string[] = []\n\n if (message) {\n const colorFn = color && colors[color] ? colors[color] : (s: string) => s\n lines.push(colorFn(message))\n }\n\n if (showTimestamp) {\n const timestamp = new Date().toISOString()\n lines.push(colors.gray(`Completed at: ${timestamp}`))\n }\n\n if (showDuration && startTime) {\n const duration = Date.now() - startTime\n const seconds = (duration / 1000).toFixed(2)\n lines.push(colors.gray(`Duration: ${seconds}s`))\n }\n\n lines.push(border)\n return lines.join('\\n')\n}\n\n/**\n * Create a summary footer with statistics and colored status indicators.\n * Automatically formats success/failure/warning counts with appropriate colors.\n * Useful for test results, build summaries, or batch operation reports.\n *\n * @param stats - Statistics to display in the summary\n * @param options - Footer formatting options\n * @returns Formatted summary footer string with colored indicators\n *\n * @example\n * ```ts\n * console.log(createSummaryFooter({\n * total: 150,\n * success: 145,\n * failed: 3,\n * skipped: 2,\n * warnings: 5\n * }))\n * // Output: Total: 150 | \u2713 145 passed | \u2717 3 failed | \u25CB 2 skipped | \u26A0 5 warnings\n * // ========================================\n * ```\n */\nexport function createSummaryFooter(\n stats: SummaryStats,\n options?: FooterOptions,\n): string {\n const parts: string[] = []\n\n if (stats.total !== undefined) {\n parts.push(`Total: ${stats.total}`)\n }\n\n if (stats.success !== undefined) {\n parts.push(colors.green(`\u2713 ${stats.success} passed`))\n }\n\n if (stats.failed !== undefined && stats.failed > 0) {\n parts.push(colors.red(`\u2717 ${stats.failed} failed`))\n }\n\n if (stats.skipped !== undefined && stats.skipped > 0) {\n parts.push(colors.yellow(`\u25CB ${stats.skipped} skipped`))\n }\n\n if (stats.warnings !== undefined && stats.warnings > 0) {\n parts.push(colors.yellow(`\u26A0 ${stats.warnings} warnings`))\n }\n\n if (stats.errors !== undefined && stats.errors > 0) {\n parts.push(colors.red(`\u2717 ${stats.errors} errors`))\n }\n\n const message = parts.join(' | ')\n return createFooter(message, {\n ...options,\n showDuration: stats.duration !== undefined,\n ...(stats.duration !== undefined && { startTime: stats.duration }),\n })\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,6BAAmB;AACnB,qBAA6B;AAgFtB,SAAS,aACd,SACA,SACQ;AACR,QAAM;AAAA,IACJ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB;AAAA,IACA,QAAQ;AAAA,EACV,IAAI,EAAE,WAAW,MAAM,GAAG,QAAQ;AAElC,QAAM,aAAS,6BAAa,YAAY,KAAK;AAC7C,QAAM,QAAkB,CAAC;AAEzB,MAAI,SAAS;AACX,UAAM,UAAU,SAAS,uBAAAA,QAAO,KAAK,IAAI,uBAAAA,QAAO,KAAK,IAAI,CAAC,MAAc;AACxE,UAAM,KAAK,QAAQ,OAAO,CAAC;AAAA,EAC7B;AAEA,MAAI,eAAe;AACjB,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,UAAM,KAAK,uBAAAA,QAAO,KAAK,iBAAiB,SAAS,EAAE,CAAC;AAAA,EACtD;AAEA,MAAI,gBAAgB,WAAW;AAC7B,UAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,UAAM,WAAW,WAAW,KAAM,QAAQ,CAAC;AAC3C,UAAM,KAAK,uBAAAA,QAAO,KAAK,aAAa,OAAO,GAAG,CAAC;AAAA,EACjD;AAEA,QAAM,KAAK,MAAM;AACjB,SAAO,MAAM,KAAK,IAAI;AACxB;AAwBO,SAAS,oBACd,OACA,SACQ;AACR,QAAM,QAAkB,CAAC;AAEzB,MAAI,MAAM,UAAU,QAAW;AAC7B,UAAM,KAAK,UAAU,MAAM,KAAK,EAAE;AAAA,EACpC;AAEA,MAAI,MAAM,YAAY,QAAW;AAC/B,UAAM,KAAK,uBAAAA,QAAO,MAAM,UAAK,MAAM,OAAO,SAAS,CAAC;AAAA,EACtD;AAEA,MAAI,MAAM,WAAW,UAAa,MAAM,SAAS,GAAG;AAClD,UAAM,KAAK,uBAAAA,QAAO,IAAI,UAAK,MAAM,MAAM,SAAS,CAAC;AAAA,EACnD;AAEA,MAAI,MAAM,YAAY,UAAa,MAAM,UAAU,GAAG;AACpD,UAAM,KAAK,uBAAAA,QAAO,OAAO,UAAK,MAAM,OAAO,UAAU,CAAC;AAAA,EACxD;AAEA,MAAI,MAAM,aAAa,UAAa,MAAM,WAAW,GAAG;AACtD,UAAM,KAAK,uBAAAA,QAAO,OAAO,UAAK,MAAM,QAAQ,WAAW,CAAC;AAAA,EAC1D;AAEA,MAAI,MAAM,WAAW,UAAa,MAAM,SAAS,GAAG;AAClD,UAAM,KAAK,uBAAAA,QAAO,IAAI,UAAK,MAAM,MAAM,SAAS,CAAC;AAAA,EACnD;AAEA,QAAM,UAAU,MAAM,KAAK,KAAK;AAChC,SAAO,aAAa,SAAS;AAAA,IAC3B,GAAG;AAAA,IACH,cAAc,MAAM,aAAa;AAAA,IACjC,GAAI,MAAM,aAAa,UAAa,EAAE,WAAW,MAAM,SAAS;AAAA,EAClE,CAAC;AACH;",
|
|
6
6
|
"names": ["colors"]
|
|
7
7
|
}
|
package/dist/stdio/header.d.ts
CHANGED
|
@@ -1,25 +1,106 @@
|
|
|
1
1
|
export interface HeaderOptions {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Width of the header in characters.
|
|
4
|
+
* @default 80
|
|
5
|
+
*/
|
|
6
|
+
width?: number | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Character to use for border lines.
|
|
9
|
+
* @default '='
|
|
10
|
+
*/
|
|
11
|
+
borderChar?: string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Number of blank lines above and below title.
|
|
14
|
+
* @default 1
|
|
15
|
+
*/
|
|
16
|
+
padding?: number | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Color to apply to the title text.
|
|
19
|
+
* @default 'cyan'
|
|
20
|
+
*/
|
|
21
|
+
color?: 'cyan' | 'green' | 'yellow' | 'blue' | 'magenta' | 'red' | 'gray' | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Apply bold styling to title.
|
|
24
|
+
* @default true
|
|
25
|
+
*/
|
|
26
|
+
bold?: boolean | undefined;
|
|
7
27
|
}
|
|
8
28
|
/**
|
|
9
|
-
* Create a formatted header/banner.
|
|
29
|
+
* Create a formatted header/banner with borders and centered title.
|
|
30
|
+
* Useful for marking the start of CLI output or creating visual sections.
|
|
31
|
+
*
|
|
32
|
+
* @param title - Title text to display in header
|
|
33
|
+
* @param options - Header formatting options
|
|
34
|
+
* @returns Formatted header string with borders and centered title
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* console.log(createHeader('Socket Security Analysis', {
|
|
39
|
+
* width: 70,
|
|
40
|
+
* color: 'cyan',
|
|
41
|
+
* bold: true,
|
|
42
|
+
* padding: 2
|
|
43
|
+
* }))
|
|
44
|
+
* // Output:
|
|
45
|
+
* // ======================================================================
|
|
46
|
+
* //
|
|
47
|
+
* // Socket Security Analysis
|
|
48
|
+
* //
|
|
49
|
+
* // ======================================================================
|
|
50
|
+
* ```
|
|
10
51
|
*/
|
|
11
52
|
export declare function createHeader(title: string, options?: HeaderOptions): string;
|
|
12
53
|
/**
|
|
13
|
-
* Create a simple section header.
|
|
54
|
+
* Create a simple section header without padding.
|
|
55
|
+
* A lighter-weight alternative to `createHeader()` for subsections.
|
|
56
|
+
*
|
|
57
|
+
* @param title - Title text to display in header
|
|
58
|
+
* @param options - Header formatting options
|
|
59
|
+
* @returns Formatted section header string
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* console.log(createSectionHeader('Dependencies', {
|
|
64
|
+
* width: 50,
|
|
65
|
+
* color: 'blue'
|
|
66
|
+
* }))
|
|
67
|
+
* // Output:
|
|
68
|
+
* // --------------------------------------------------
|
|
69
|
+
* // Dependencies
|
|
70
|
+
* // --------------------------------------------------
|
|
71
|
+
* ```
|
|
14
72
|
*/
|
|
15
73
|
export declare function createSectionHeader(title: string, options?: HeaderOptions): string;
|
|
16
74
|
/**
|
|
17
|
-
* Print a header directly to stdout.
|
|
18
|
-
*
|
|
75
|
+
* Print a header directly to stdout with standard formatting.
|
|
76
|
+
* Uses fixed width of 55 characters with `═` borders.
|
|
77
|
+
* Simpler alternative to `createHeader()` for quick headers.
|
|
78
|
+
*
|
|
79
|
+
* @param title - Title text to display
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* printHeader('Package Analysis')
|
|
84
|
+
* // Output:
|
|
85
|
+
* // ═══════════════════════════════════════════════════
|
|
86
|
+
* // Package Analysis
|
|
87
|
+
* // ═══════════════════════════════════════════════════
|
|
88
|
+
* ```
|
|
19
89
|
*/
|
|
20
90
|
export declare function printHeader(title: string): void;
|
|
21
91
|
/**
|
|
22
|
-
* Print a footer with optional message.
|
|
23
|
-
* Uses
|
|
92
|
+
* Print a footer with optional success message.
|
|
93
|
+
* Uses `─` border character for a lighter appearance.
|
|
94
|
+
* Fixed width of 55 characters to match `printHeader()`.
|
|
95
|
+
*
|
|
96
|
+
* @param message - Optional message to display (shown in green)
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* printFooter('Analysis complete')
|
|
101
|
+
* // Output:
|
|
102
|
+
* // ───────────────────────────────────────────────────
|
|
103
|
+
* // Analysis complete (in green)
|
|
104
|
+
* ```
|
|
24
105
|
*/
|
|
25
|
-
export declare function printFooter(message?: string): void;
|
|
106
|
+
export declare function printFooter(message?: string | undefined): void;
|
package/dist/stdio/header.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/stdio/header.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Console header/banner formatting utilities.\n * Provides consistent header formatting for CLI applications.\n */\n\nimport colors from '../external/yoctocolors-cjs'\nimport { centerText, repeatString } from '../strings'\n\nexport interface HeaderOptions {\n width?: number\n borderChar?: string\n padding?: number\n color
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,6BAAmB;AACnB,qBAAyC;
|
|
4
|
+
"sourcesContent": ["/**\n * @fileoverview Console header/banner formatting utilities.\n * Provides consistent header formatting for CLI applications.\n */\n\nimport colors from '../external/yoctocolors-cjs'\nimport { centerText, repeatString } from '../strings'\n\nexport interface HeaderOptions {\n /**\n * Width of the header in characters.\n * @default 80\n */\n width?: number | undefined\n /**\n * Character to use for border lines.\n * @default '='\n */\n borderChar?: string | undefined\n /**\n * Number of blank lines above and below title.\n * @default 1\n */\n padding?: number | undefined\n /**\n * Color to apply to the title text.\n * @default 'cyan'\n */\n color?:\n | 'cyan'\n | 'green'\n | 'yellow'\n | 'blue'\n | 'magenta'\n | 'red'\n | 'gray'\n | undefined\n /**\n * Apply bold styling to title.\n * @default true\n */\n bold?: boolean | undefined\n}\n\n/**\n * Create a formatted header/banner with borders and centered title.\n * Useful for marking the start of CLI output or creating visual sections.\n *\n * @param title - Title text to display in header\n * @param options - Header formatting options\n * @returns Formatted header string with borders and centered title\n *\n * @example\n * ```ts\n * console.log(createHeader('Socket Security Analysis', {\n * width: 70,\n * color: 'cyan',\n * bold: true,\n * padding: 2\n * }))\n * // Output:\n * // ======================================================================\n * //\n * // Socket Security Analysis\n * //\n * // ======================================================================\n * ```\n */\nexport function createHeader(title: string, options?: HeaderOptions): string {\n const {\n bold = true,\n borderChar = '=',\n color = 'cyan',\n padding = 1,\n width = 80,\n } = { __proto__: null, ...options } as HeaderOptions\n\n const border = repeatString(borderChar, width)\n\n // Apply color and bold\n let formattedTitle = title\n if (color && colors[color]) {\n formattedTitle = colors[color](formattedTitle)\n }\n if (bold && colors.bold) {\n formattedTitle = colors.bold(formattedTitle)\n }\n\n const centeredTitle = centerText(formattedTitle, width)\n const paddingLine = repeatString(' ', width)\n\n const lines: string[] = [border]\n\n for (let i = 0; i < padding; i++) {\n lines.push(paddingLine)\n }\n\n lines.push(centeredTitle)\n\n for (let i = 0; i < padding; i++) {\n lines.push(paddingLine)\n }\n\n lines.push(border)\n\n return lines.join('\\n')\n}\n\n/**\n * Create a simple section header without padding.\n * A lighter-weight alternative to `createHeader()` for subsections.\n *\n * @param title - Title text to display in header\n * @param options - Header formatting options\n * @returns Formatted section header string\n *\n * @example\n * ```ts\n * console.log(createSectionHeader('Dependencies', {\n * width: 50,\n * color: 'blue'\n * }))\n * // Output:\n * // --------------------------------------------------\n * // Dependencies\n * // --------------------------------------------------\n * ```\n */\nexport function createSectionHeader(\n title: string,\n options?: HeaderOptions,\n): string {\n const {\n borderChar = '-',\n color = 'blue',\n width = 60,\n } = { __proto__: null, ...options } as HeaderOptions\n\n return createHeader(title, {\n width,\n borderChar,\n padding: 0,\n color,\n bold: false,\n })\n}\n\n/**\n * Print a header directly to stdout with standard formatting.\n * Uses fixed width of 55 characters with `\u2550` borders.\n * Simpler alternative to `createHeader()` for quick headers.\n *\n * @param title - Title text to display\n *\n * @example\n * ```ts\n * printHeader('Package Analysis')\n * // Output:\n * // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n * // Package Analysis\n * // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n * ```\n */\nexport function printHeader(title: string): void {\n const border = repeatString('\u2550', 55)\n console.log(border)\n console.log(` ${title}`)\n console.log(border)\n}\n\n/**\n * Print a footer with optional success message.\n * Uses `\u2500` border character for a lighter appearance.\n * Fixed width of 55 characters to match `printHeader()`.\n *\n * @param message - Optional message to display (shown in green)\n *\n * @example\n * ```ts\n * printFooter('Analysis complete')\n * // Output:\n * // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * // Analysis complete (in green)\n * ```\n */\nexport function printFooter(message?: string | undefined): void {\n const border = repeatString('\u2500', 55)\n console.log(border)\n if (message) {\n console.log(colors.green(message))\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,6BAAmB;AACnB,qBAAyC;AA8DlC,SAAS,aAAa,OAAe,SAAiC;AAC3E,QAAM;AAAA,IACJ,OAAO;AAAA,IACP,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,QAAQ;AAAA,EACV,IAAI,EAAE,WAAW,MAAM,GAAG,QAAQ;AAElC,QAAM,aAAS,6BAAa,YAAY,KAAK;AAG7C,MAAI,iBAAiB;AACrB,MAAI,SAAS,uBAAAA,QAAO,KAAK,GAAG;AAC1B,qBAAiB,uBAAAA,QAAO,KAAK,EAAE,cAAc;AAAA,EAC/C;AACA,MAAI,QAAQ,uBAAAA,QAAO,MAAM;AACvB,qBAAiB,uBAAAA,QAAO,KAAK,cAAc;AAAA,EAC7C;AAEA,QAAM,oBAAgB,2BAAW,gBAAgB,KAAK;AACtD,QAAM,kBAAc,6BAAa,KAAK,KAAK;AAE3C,QAAM,QAAkB,CAAC,MAAM;AAE/B,WAAS,IAAI,GAAG,IAAI,SAAS,KAAK;AAChC,UAAM,KAAK,WAAW;AAAA,EACxB;AAEA,QAAM,KAAK,aAAa;AAExB,WAAS,IAAI,GAAG,IAAI,SAAS,KAAK;AAChC,UAAM,KAAK,WAAW;AAAA,EACxB;AAEA,QAAM,KAAK,MAAM;AAEjB,SAAO,MAAM,KAAK,IAAI;AACxB;AAsBO,SAAS,oBACd,OACA,SACQ;AACR,QAAM;AAAA,IACJ,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,IAAI,EAAE,WAAW,MAAM,GAAG,QAAQ;AAElC,SAAO,aAAa,OAAO;AAAA,IACzB;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IACA,MAAM;AAAA,EACR,CAAC;AACH;AAkBO,SAAS,YAAY,OAAqB;AAC/C,QAAM,aAAS,6BAAa,UAAK,EAAE;AACnC,UAAQ,IAAI,MAAM;AAClB,UAAQ,IAAI,KAAK,KAAK,EAAE;AACxB,UAAQ,IAAI,MAAM;AACpB;AAiBO,SAAS,YAAY,SAAoC;AAC9D,QAAM,aAAS,6BAAa,UAAK,EAAE;AACnC,UAAQ,IAAI,MAAM;AAClB,MAAI,SAAS;AACX,YAAQ,IAAI,uBAAAA,QAAO,MAAM,OAAO,CAAC;AAAA,EACnC;AACF;",
|
|
6
6
|
"names": ["colors"]
|
|
7
7
|
}
|
package/dist/stdio/mask.d.ts
CHANGED
|
@@ -20,24 +20,92 @@
|
|
|
20
20
|
import type { ChildProcess, SpawnOptions } from 'node:child_process';
|
|
21
21
|
import readline from 'node:readline';
|
|
22
22
|
export interface OutputMaskOptions {
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Current working directory for spawned process.
|
|
25
|
+
* @default process.cwd()
|
|
26
|
+
*/
|
|
27
|
+
cwd?: string | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Environment variables for spawned process.
|
|
30
|
+
* @default process.env
|
|
31
|
+
*/
|
|
32
|
+
env?: NodeJS.ProcessEnv | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Filter output before displaying or buffering.
|
|
35
|
+
* Return `false` to skip the line, `true` to include it.
|
|
36
|
+
*
|
|
37
|
+
* Useful for filtering non-fatal warnings or noise from test runners.
|
|
38
|
+
* The filter runs on every chunk of output before display/buffering.
|
|
39
|
+
*
|
|
40
|
+
* @param text - The output text chunk (may include ANSI codes)
|
|
41
|
+
* @param stream - Whether this came from 'stdout' or 'stderr'
|
|
42
|
+
* @returns `true` to include this output, `false` to skip it
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* filterOutput: (text, stream) => {
|
|
47
|
+
* // Skip vitest worker termination errors
|
|
48
|
+
* if (text.includes('Terminating worker thread')) return false
|
|
49
|
+
* return true
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
filterOutput?: ((text: string, stream: 'stdout' | 'stderr') => boolean) | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* Progress message to display in spinner.
|
|
56
|
+
* @default 'Running…'
|
|
57
|
+
*/
|
|
58
|
+
message?: string | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Override the exit code based on captured output.
|
|
61
|
+
*
|
|
62
|
+
* Useful for handling non-fatal errors that shouldn't fail the build.
|
|
63
|
+
* Called after the process exits with the original code and all captured output.
|
|
64
|
+
* Return a number to override the exit code, or `undefined` to keep original.
|
|
65
|
+
*
|
|
66
|
+
* @param code - Original exit code from the process
|
|
67
|
+
* @param stdout - All captured stdout (even filtered lines are captured)
|
|
68
|
+
* @param stderr - All captured stderr (even filtered lines are captured)
|
|
69
|
+
* @returns New exit code, or `undefined` to keep original
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* overrideExitCode: (code, stdout, stderr) => {
|
|
74
|
+
* // If only worker termination errors, treat as success
|
|
75
|
+
* const output = stdout + stderr
|
|
76
|
+
* const hasWorkerError = output.includes('Terminating worker thread')
|
|
77
|
+
* const hasRealFailure = output.includes('FAIL')
|
|
78
|
+
* if (code !== 0 && hasWorkerError && !hasRealFailure) {
|
|
79
|
+
* return 0 // Override to success
|
|
80
|
+
* }
|
|
81
|
+
* return undefined // Keep original
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
overrideExitCode?: ((code: number, stdout: string, stderr: string) => number | undefined) | undefined;
|
|
86
|
+
/**
|
|
87
|
+
* Start with output visible instead of masked.
|
|
88
|
+
* When `true`, output shows immediately without needing ctrl+o.
|
|
89
|
+
* @default false
|
|
90
|
+
*/
|
|
91
|
+
showOutput?: boolean | undefined;
|
|
92
|
+
/**
|
|
93
|
+
* Text to show after "ctrl+o" in spinner message.
|
|
94
|
+
* @default 'to see full output'
|
|
95
|
+
*/
|
|
96
|
+
toggleText?: string | undefined;
|
|
33
97
|
}
|
|
34
98
|
export interface OutputMask {
|
|
35
|
-
/** Whether output is currently visible */
|
|
36
|
-
verbose: boolean;
|
|
37
|
-
/** Buffered output lines */
|
|
38
|
-
outputBuffer: string[];
|
|
39
99
|
/** Whether spinner is currently active */
|
|
40
100
|
isSpinning: boolean;
|
|
101
|
+
/** Buffered output lines */
|
|
102
|
+
outputBuffer: string[];
|
|
103
|
+
/** All stderr captured (for exit code override) */
|
|
104
|
+
stderrCapture: string;
|
|
105
|
+
/** All stdout captured (for exit code override) */
|
|
106
|
+
stdoutCapture: string;
|
|
107
|
+
/** Whether output is currently visible */
|
|
108
|
+
verbose: boolean;
|
|
41
109
|
}
|
|
42
110
|
/**
|
|
43
111
|
* Create an output mask for controlling command output visibility.
|
package/dist/stdio/mask.js
CHANGED
|
@@ -42,9 +42,11 @@ var import_stdout = require("./stdout.js");
|
|
|
42
42
|
function createOutputMask(options = {}) {
|
|
43
43
|
const { showOutput = false } = options;
|
|
44
44
|
return {
|
|
45
|
-
|
|
45
|
+
isSpinning: !showOutput,
|
|
46
46
|
outputBuffer: [],
|
|
47
|
-
|
|
47
|
+
stderrCapture: "",
|
|
48
|
+
stdoutCapture: "",
|
|
49
|
+
verbose: showOutput
|
|
48
50
|
};
|
|
49
51
|
}
|
|
50
52
|
function createKeyboardHandler(mask, child, options = {}) {
|
|
@@ -111,6 +113,10 @@ function attachOutputMask(child, options = {}) {
|
|
|
111
113
|
if (child.stdout) {
|
|
112
114
|
child.stdout.on("data", (data) => {
|
|
113
115
|
const text = data.toString();
|
|
116
|
+
mask.stdoutCapture += text;
|
|
117
|
+
if (options.filterOutput && !options.filterOutput(text, "stdout")) {
|
|
118
|
+
return void 0;
|
|
119
|
+
}
|
|
114
120
|
if (mask.verbose) {
|
|
115
121
|
(0, import_stdout.write)(text);
|
|
116
122
|
} else {
|
|
@@ -126,6 +132,10 @@ function attachOutputMask(child, options = {}) {
|
|
|
126
132
|
if (child.stderr) {
|
|
127
133
|
child.stderr.on("data", (data) => {
|
|
128
134
|
const text = data.toString();
|
|
135
|
+
mask.stderrCapture += text;
|
|
136
|
+
if (options.filterOutput && !options.filterOutput(text, "stderr")) {
|
|
137
|
+
return void 0;
|
|
138
|
+
}
|
|
129
139
|
if (mask.verbose) {
|
|
130
140
|
process.stderr.write(text);
|
|
131
141
|
} else {
|
|
@@ -138,8 +148,19 @@ function attachOutputMask(child, options = {}) {
|
|
|
138
148
|
if (process.stdin.isTTY) {
|
|
139
149
|
process.stdin.setRawMode(false);
|
|
140
150
|
}
|
|
151
|
+
let finalCode = code || 0;
|
|
152
|
+
if (options.overrideExitCode) {
|
|
153
|
+
const overridden = options.overrideExitCode(
|
|
154
|
+
finalCode,
|
|
155
|
+
mask.stdoutCapture,
|
|
156
|
+
mask.stderrCapture
|
|
157
|
+
);
|
|
158
|
+
if (overridden !== void 0) {
|
|
159
|
+
finalCode = overridden;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
141
162
|
if (mask.isSpinning) {
|
|
142
|
-
if (
|
|
163
|
+
if (finalCode === 0) {
|
|
143
164
|
import_spinner.spinner.successAndStop(`${message} completed`);
|
|
144
165
|
} else {
|
|
145
166
|
import_spinner.spinner.failAndStop(`${message} failed`);
|
|
@@ -151,7 +172,7 @@ function attachOutputMask(child, options = {}) {
|
|
|
151
172
|
}
|
|
152
173
|
}
|
|
153
174
|
}
|
|
154
|
-
resolve(
|
|
175
|
+
resolve(finalCode);
|
|
155
176
|
});
|
|
156
177
|
child.on("error", (error) => {
|
|
157
178
|
if (process.stdin.isTTY) {
|
package/dist/stdio/mask.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/stdio/mask.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @fileoverview Interactive output masking utilities for CLI tools.\n * Provides output control with keyboard toggling (ctrl+o).\n *\n * ANSI Escape Sequences Used:\n * - '\\r': Carriage return - moves cursor to beginning of current line.\n * - '\\x1b[K' or '\\x1b[0K': CSI K (erase line) - clear from cursor to end of line.\n * - '\\x1b[2K': CSI 2K - erase entire line.\n * - '\\x1b[1A': CSI A - move cursor up 1 line.\n *\n * Terminal Control:\n * - Raw mode (setRawMode(true)): Captures keypresses immediately without buffering.\n * - TTY detection: Ensures terminal manipulation only occurs in interactive terminals.\n *\n * Key Features:\n * - Output buffering: Stores up to 1000 lines when masked to prevent memory issues.\n * - Graceful cleanup: Always restores terminal to normal mode on exit/error.\n * - Visual feedback: Uses spinner to indicate process is running when output is masked.\n */\n\nimport type { ChildProcess, SpawnOptions } from 'node:child_process'\nimport { spawn } from 'node:child_process'\nimport readline from 'node:readline'\nimport { spinner } from '../spinner.js'\nimport { clearLine } from './clear.js'\nimport { write } from './stdout.js'\n\nexport interface OutputMaskOptions {\n /** Current working directory */\n cwd?: string\n /** Environment variables */\n env?: NodeJS.ProcessEnv\n /** Progress message to display */\n message?: string\n /** Show output by default instead of masking it */\n showOutput?: boolean\n /** Text to show after \"ctrl+o\" in spinner */\n toggleText?: string\n}\n\nexport interface OutputMask {\n /** Whether output is currently visible */\n verbose: boolean\n /** Buffered output lines */\n outputBuffer: string[]\n /** Whether spinner is currently active */\n isSpinning: boolean\n}\n\n/**\n * Create an output mask for controlling command output visibility.\n * The mask tracks whether output should be shown or hidden (buffered).\n * When hidden, output is buffered and a spinner is shown instead.\n */\nexport function createOutputMask(options: OutputMaskOptions = {}): OutputMask {\n const { showOutput = false } = options\n\n return {\n verbose: showOutput,\n outputBuffer: [],\n isSpinning: !showOutput,\n }\n}\n\n/**\n * Create a keyboard handler for toggling output visibility.\n * Handles two key combinations:\n * - ctrl+o: Toggle between showing and hiding output.\n * - ctrl+c: Cancel the running process.\n * The handler manipulates terminal state using ANSI escape sequences.\n */\nexport function createKeyboardHandler(\n mask: OutputMask,\n child: ChildProcess,\n options: OutputMaskOptions = {},\n): (_str: string, key: readline.Key) => void {\n const { message = 'Running\u2026', toggleText = 'to see full output' } = options\n\n return (_str, key) => {\n // ctrl+o toggles verbose mode.\n if (key?.ctrl && key.name === 'o') {\n mask.verbose = !mask.verbose\n\n if (mask.verbose) {\n // Stop spinner and show buffered output.\n if (mask.isSpinning) {\n spinner.stop()\n mask.isSpinning = false\n }\n\n // Clear the current line (removes spinner remnants).\n clearLine()\n\n // Show buffered output.\n if (mask.outputBuffer.length > 0) {\n console.log('--- Output (ctrl+o to hide) ---')\n mask.outputBuffer.forEach(line => {\n write(line)\n })\n }\n } else {\n // Hide output and show spinner.\n // Clear all the output lines that were shown.\n if (mask.outputBuffer.length > 0) {\n // Calculate number of lines to clear (output + header line).\n const lineCount = mask.outputBuffer.join('').split('\\n').length + 1\n // Move up and clear each line using ANSI escape sequences:\n // - '\\x1b[1A' (CSI A): Move cursor up 1 line.\n // - '\\x1b[2K' (CSI K with param 2): Erase entire line.\n // This combination effectively \"rewinds\" the terminal output.\n for (let i = 0; i < lineCount; i += 1) {\n process.stdout.write('\\x1b[1A\\x1b[2K')\n }\n }\n clearLine()\n\n // Clear the buffer and restart spinner.\n mask.outputBuffer = []\n if (!mask.isSpinning) {\n spinner.start(`${message} (ctrl+o ${toggleText})`)\n mask.isSpinning = true\n }\n }\n }\n // ctrl+c to cancel.\n else if (key?.ctrl && key.name === 'c') {\n // Gracefully terminate child process.\n child.kill('SIGTERM')\n // Restore terminal to normal mode before exiting.\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false)\n }\n throw new Error('Process cancelled by user')\n }\n }\n}\n\n/**\n * Attach output masking to a child process.\n * Returns a promise that resolves with the exit code.\n * This function:\n * - Sets up keyboard input handling in raw mode for immediate key capture.\n * - Buffers stdout/stderr when not in verbose mode.\n * - Shows a spinner when output is masked.\n * - Allows toggling between masked and unmasked output with ctrl+o.\n */\nexport function attachOutputMask(\n child: ChildProcess,\n options: OutputMaskOptions = {},\n): Promise<number> {\n return new Promise((resolve, reject) => {\n const { message = 'Running\u2026' } = options\n const mask = createOutputMask(options)\n\n // Start spinner if not verbose.\n if (mask.isSpinning && process.stdout.isTTY) {\n spinner.start(\n `${message} (ctrl+o ${options.toggleText || 'to see full output'})`,\n )\n }\n\n // Setup keyboard input handling.\n // Raw mode is required to capture ctrl+o without waiting for Enter.\n if (process.stdin.isTTY) {\n readline.emitKeypressEvents(process.stdin)\n process.stdin.setRawMode(true)\n\n const keypressHandler = createKeyboardHandler(mask, child, options)\n process.stdin.on('keypress', keypressHandler)\n\n // Cleanup on exit: restore terminal to normal mode.\n child.on('exit', () => {\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false)\n process.stdin.removeListener('keypress', keypressHandler)\n }\n })\n }\n\n // Handle stdout: either show immediately or buffer for later.\n if (child.stdout) {\n child.stdout.on('data', data => {\n const text = data.toString()\n if (mask.verbose) {\n write(text)\n } else {\n // Buffer the output for later.\n mask.outputBuffer.push(text)\n\n // Keep buffer size reasonable (last 1000 lines).\n // This prevents unbounded memory growth for long-running processes.\n const lines = mask.outputBuffer.join('').split('\\n')\n if (lines.length > 1000) {\n mask.outputBuffer = [lines.slice(-1000).join('\\n')]\n }\n }\n return undefined\n })\n }\n\n // Handle stderr: same as stdout, but write to stderr stream when verbose.\n if (child.stderr) {\n child.stderr.on('data', data => {\n const text = data.toString()\n if (mask.verbose) {\n process.stderr.write(text)\n } else {\n mask.outputBuffer.push(text)\n }\n return undefined\n })\n }\n\n child.on('exit', code => {\n // Cleanup keyboard if needed.\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false)\n }\n\n if (mask.isSpinning) {\n if (code === 0) {\n spinner.successAndStop(`${message} completed`)\n } else {\n spinner.failAndStop(`${message} failed`)\n // Show buffered output on failure so user can see what went wrong.\n if (mask.outputBuffer.length > 0 && !mask.verbose) {\n console.log('\\n--- Output ---')\n mask.outputBuffer.forEach(line => {\n write(line)\n })\n }\n }\n }\n\n resolve(code || 0)\n })\n\n child.on('error', error => {\n // Ensure terminal is restored to normal mode on error.\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false)\n }\n\n if (mask.isSpinning) {\n spinner.failAndStop(`${message} error`)\n }\n reject(error)\n })\n })\n}\n\n/**\n * Run a command with interactive output masking.\n * Convenience wrapper around spawn + attachOutputMask.\n * Spawns a child process and attaches the output masking system to it.\n * stdin is inherited, stdout and stderr are piped for masking control.\n */\nexport async function runWithMask(\n command: string,\n args: string[] = [],\n options: OutputMaskOptions & SpawnOptions = {},\n): Promise<number> {\n const {\n message = 'Running\u2026',\n showOutput = false,\n toggleText = 'to see output',\n ...spawnOptions\n } = options\n\n const child = spawn(command, args, {\n stdio: ['inherit', 'pipe', 'pipe'],\n ...spawnOptions,\n })\n\n return await attachOutputMask(child, { message, showOutput, toggleText })\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBA,gCAAsB;AACtB,2BAAqB;AACrB,qBAAwB;AACxB,mBAA0B;AAC1B,oBAAsB;
|
|
4
|
+
"sourcesContent": ["/**\n * @fileoverview Interactive output masking utilities for CLI tools.\n * Provides output control with keyboard toggling (ctrl+o).\n *\n * ANSI Escape Sequences Used:\n * - '\\r': Carriage return - moves cursor to beginning of current line.\n * - '\\x1b[K' or '\\x1b[0K': CSI K (erase line) - clear from cursor to end of line.\n * - '\\x1b[2K': CSI 2K - erase entire line.\n * - '\\x1b[1A': CSI A - move cursor up 1 line.\n *\n * Terminal Control:\n * - Raw mode (setRawMode(true)): Captures keypresses immediately without buffering.\n * - TTY detection: Ensures terminal manipulation only occurs in interactive terminals.\n *\n * Key Features:\n * - Output buffering: Stores up to 1000 lines when masked to prevent memory issues.\n * - Graceful cleanup: Always restores terminal to normal mode on exit/error.\n * - Visual feedback: Uses spinner to indicate process is running when output is masked.\n */\n\nimport type { ChildProcess, SpawnOptions } from 'node:child_process'\nimport { spawn } from 'node:child_process'\nimport readline from 'node:readline'\nimport { spinner } from '../spinner.js'\nimport { clearLine } from './clear.js'\nimport { write } from './stdout.js'\n\nexport interface OutputMaskOptions {\n /**\n * Current working directory for spawned process.\n * @default process.cwd()\n */\n cwd?: string | undefined\n /**\n * Environment variables for spawned process.\n * @default process.env\n */\n env?: NodeJS.ProcessEnv | undefined\n /**\n * Filter output before displaying or buffering.\n * Return `false` to skip the line, `true` to include it.\n *\n * Useful for filtering non-fatal warnings or noise from test runners.\n * The filter runs on every chunk of output before display/buffering.\n *\n * @param text - The output text chunk (may include ANSI codes)\n * @param stream - Whether this came from 'stdout' or 'stderr'\n * @returns `true` to include this output, `false` to skip it\n *\n * @example\n * ```ts\n * filterOutput: (text, stream) => {\n * // Skip vitest worker termination errors\n * if (text.includes('Terminating worker thread')) return false\n * return true\n * }\n * ```\n */\n filterOutput?:\n | ((text: string, stream: 'stdout' | 'stderr') => boolean)\n | undefined\n /**\n * Progress message to display in spinner.\n * @default 'Running\u2026'\n */\n message?: string | undefined\n /**\n * Override the exit code based on captured output.\n *\n * Useful for handling non-fatal errors that shouldn't fail the build.\n * Called after the process exits with the original code and all captured output.\n * Return a number to override the exit code, or `undefined` to keep original.\n *\n * @param code - Original exit code from the process\n * @param stdout - All captured stdout (even filtered lines are captured)\n * @param stderr - All captured stderr (even filtered lines are captured)\n * @returns New exit code, or `undefined` to keep original\n *\n * @example\n * ```ts\n * overrideExitCode: (code, stdout, stderr) => {\n * // If only worker termination errors, treat as success\n * const output = stdout + stderr\n * const hasWorkerError = output.includes('Terminating worker thread')\n * const hasRealFailure = output.includes('FAIL')\n * if (code !== 0 && hasWorkerError && !hasRealFailure) {\n * return 0 // Override to success\n * }\n * return undefined // Keep original\n * }\n * ```\n */\n overrideExitCode?:\n | ((code: number, stdout: string, stderr: string) => number | undefined)\n | undefined\n /**\n * Start with output visible instead of masked.\n * When `true`, output shows immediately without needing ctrl+o.\n * @default false\n */\n showOutput?: boolean | undefined\n /**\n * Text to show after \"ctrl+o\" in spinner message.\n * @default 'to see full output'\n */\n toggleText?: string | undefined\n}\n\nexport interface OutputMask {\n /** Whether spinner is currently active */\n isSpinning: boolean\n /** Buffered output lines */\n outputBuffer: string[]\n /** All stderr captured (for exit code override) */\n stderrCapture: string\n /** All stdout captured (for exit code override) */\n stdoutCapture: string\n /** Whether output is currently visible */\n verbose: boolean\n}\n\n/**\n * Create an output mask for controlling command output visibility.\n * The mask tracks whether output should be shown or hidden (buffered).\n * When hidden, output is buffered and a spinner is shown instead.\n */\nexport function createOutputMask(options: OutputMaskOptions = {}): OutputMask {\n const { showOutput = false } = options\n\n return {\n isSpinning: !showOutput,\n outputBuffer: [],\n stderrCapture: '',\n stdoutCapture: '',\n verbose: showOutput,\n }\n}\n\n/**\n * Create a keyboard handler for toggling output visibility.\n * Handles two key combinations:\n * - ctrl+o: Toggle between showing and hiding output.\n * - ctrl+c: Cancel the running process.\n * The handler manipulates terminal state using ANSI escape sequences.\n */\nexport function createKeyboardHandler(\n mask: OutputMask,\n child: ChildProcess,\n options: OutputMaskOptions = {},\n): (_str: string, key: readline.Key) => void {\n const { message = 'Running\u2026', toggleText = 'to see full output' } = options\n\n return (_str, key) => {\n // ctrl+o toggles verbose mode.\n if (key?.ctrl && key.name === 'o') {\n mask.verbose = !mask.verbose\n\n if (mask.verbose) {\n // Stop spinner and show buffered output.\n if (mask.isSpinning) {\n spinner.stop()\n mask.isSpinning = false\n }\n\n // Clear the current line (removes spinner remnants).\n clearLine()\n\n // Show buffered output.\n if (mask.outputBuffer.length > 0) {\n console.log('--- Output (ctrl+o to hide) ---')\n mask.outputBuffer.forEach(line => {\n write(line)\n })\n }\n } else {\n // Hide output and show spinner.\n // Clear all the output lines that were shown.\n if (mask.outputBuffer.length > 0) {\n // Calculate number of lines to clear (output + header line).\n const lineCount = mask.outputBuffer.join('').split('\\n').length + 1\n // Move up and clear each line using ANSI escape sequences:\n // - '\\x1b[1A' (CSI A): Move cursor up 1 line.\n // - '\\x1b[2K' (CSI K with param 2): Erase entire line.\n // This combination effectively \"rewinds\" the terminal output.\n for (let i = 0; i < lineCount; i += 1) {\n process.stdout.write('\\x1b[1A\\x1b[2K')\n }\n }\n clearLine()\n\n // Clear the buffer and restart spinner.\n mask.outputBuffer = []\n if (!mask.isSpinning) {\n spinner.start(`${message} (ctrl+o ${toggleText})`)\n mask.isSpinning = true\n }\n }\n }\n // ctrl+c to cancel.\n else if (key?.ctrl && key.name === 'c') {\n // Gracefully terminate child process.\n child.kill('SIGTERM')\n // Restore terminal to normal mode before exiting.\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false)\n }\n throw new Error('Process cancelled by user')\n }\n }\n}\n\n/**\n * Attach output masking to a child process.\n * Returns a promise that resolves with the exit code.\n * This function:\n * - Sets up keyboard input handling in raw mode for immediate key capture.\n * - Buffers stdout/stderr when not in verbose mode.\n * - Shows a spinner when output is masked.\n * - Allows toggling between masked and unmasked output with ctrl+o.\n */\nexport function attachOutputMask(\n child: ChildProcess,\n options: OutputMaskOptions = {},\n): Promise<number> {\n return new Promise((resolve, reject) => {\n const { message = 'Running\u2026' } = options\n const mask = createOutputMask(options)\n\n // Start spinner if not verbose.\n if (mask.isSpinning && process.stdout.isTTY) {\n spinner.start(\n `${message} (ctrl+o ${options.toggleText || 'to see full output'})`,\n )\n }\n\n // Setup keyboard input handling.\n // Raw mode is required to capture ctrl+o without waiting for Enter.\n if (process.stdin.isTTY) {\n readline.emitKeypressEvents(process.stdin)\n process.stdin.setRawMode(true)\n\n const keypressHandler = createKeyboardHandler(mask, child, options)\n process.stdin.on('keypress', keypressHandler)\n\n // Cleanup on exit: restore terminal to normal mode.\n child.on('exit', () => {\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false)\n process.stdin.removeListener('keypress', keypressHandler)\n }\n })\n }\n\n // Handle stdout: either show immediately or buffer for later.\n if (child.stdout) {\n child.stdout.on('data', data => {\n const text = data.toString()\n\n // Always capture for exit code override.\n mask.stdoutCapture += text\n\n // Apply filter if provided.\n if (options.filterOutput && !options.filterOutput(text, 'stdout')) {\n // Skip this output.\n return undefined\n }\n\n if (mask.verbose) {\n write(text)\n } else {\n // Buffer the output for later.\n mask.outputBuffer.push(text)\n\n // Keep buffer size reasonable (last 1000 lines).\n // This prevents unbounded memory growth for long-running processes.\n const lines = mask.outputBuffer.join('').split('\\n')\n if (lines.length > 1000) {\n mask.outputBuffer = [lines.slice(-1000).join('\\n')]\n }\n }\n return undefined\n })\n }\n\n // Handle stderr: same as stdout, but write to stderr stream when verbose.\n if (child.stderr) {\n child.stderr.on('data', data => {\n const text = data.toString()\n\n // Always capture for exit code override.\n mask.stderrCapture += text\n\n // Apply filter if provided.\n if (options.filterOutput && !options.filterOutput(text, 'stderr')) {\n // Skip this output.\n return undefined\n }\n\n if (mask.verbose) {\n process.stderr.write(text)\n } else {\n mask.outputBuffer.push(text)\n }\n return undefined\n })\n }\n\n child.on('exit', code => {\n // Cleanup keyboard if needed.\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false)\n }\n\n // Allow caller to override exit code based on output.\n let finalCode = code || 0\n if (options.overrideExitCode) {\n const overridden = options.overrideExitCode(\n finalCode,\n mask.stdoutCapture,\n mask.stderrCapture,\n )\n if (overridden !== undefined) {\n finalCode = overridden\n }\n }\n\n if (mask.isSpinning) {\n if (finalCode === 0) {\n spinner.successAndStop(`${message} completed`)\n } else {\n spinner.failAndStop(`${message} failed`)\n // Show buffered output on failure so user can see what went wrong.\n if (mask.outputBuffer.length > 0 && !mask.verbose) {\n console.log('\\n--- Output ---')\n mask.outputBuffer.forEach(line => {\n write(line)\n })\n }\n }\n }\n\n resolve(finalCode)\n })\n\n child.on('error', error => {\n // Ensure terminal is restored to normal mode on error.\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false)\n }\n\n if (mask.isSpinning) {\n spinner.failAndStop(`${message} error`)\n }\n reject(error)\n })\n })\n}\n\n/**\n * Run a command with interactive output masking.\n * Convenience wrapper around spawn + attachOutputMask.\n * Spawns a child process and attaches the output masking system to it.\n * stdin is inherited, stdout and stderr are piped for masking control.\n */\nexport async function runWithMask(\n command: string,\n args: string[] = [],\n options: OutputMaskOptions & SpawnOptions = {},\n): Promise<number> {\n const {\n message = 'Running\u2026',\n showOutput = false,\n toggleText = 'to see output',\n ...spawnOptions\n } = options\n\n const child = spawn(command, args, {\n stdio: ['inherit', 'pipe', 'pipe'],\n ...spawnOptions,\n })\n\n return await attachOutputMask(child, { message, showOutput, toggleText })\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBA,gCAAsB;AACtB,2BAAqB;AACrB,qBAAwB;AACxB,mBAA0B;AAC1B,oBAAsB;AAqGf,SAAS,iBAAiB,UAA6B,CAAC,GAAe;AAC5E,QAAM,EAAE,aAAa,MAAM,IAAI;AAE/B,SAAO;AAAA,IACL,YAAY,CAAC;AAAA,IACb,cAAc,CAAC;AAAA,IACf,eAAe;AAAA,IACf,eAAe;AAAA,IACf,SAAS;AAAA,EACX;AACF;AASO,SAAS,sBACd,MACA,OACA,UAA6B,CAAC,GACa;AAC3C,QAAM,EAAE,UAAU,iBAAY,aAAa,qBAAqB,IAAI;AAEpE,SAAO,CAAC,MAAM,QAAQ;AAEpB,QAAI,KAAK,QAAQ,IAAI,SAAS,KAAK;AACjC,WAAK,UAAU,CAAC,KAAK;AAErB,UAAI,KAAK,SAAS;AAEhB,YAAI,KAAK,YAAY;AACnB,iCAAQ,KAAK;AACb,eAAK,aAAa;AAAA,QACpB;AAGA,oCAAU;AAGV,YAAI,KAAK,aAAa,SAAS,GAAG;AAChC,kBAAQ,IAAI,iCAAiC;AAC7C,eAAK,aAAa,QAAQ,UAAQ;AAChC,qCAAM,IAAI;AAAA,UACZ,CAAC;AAAA,QACH;AAAA,MACF,OAAO;AAGL,YAAI,KAAK,aAAa,SAAS,GAAG;AAEhC,gBAAM,YAAY,KAAK,aAAa,KAAK,EAAE,EAAE,MAAM,IAAI,EAAE,SAAS;AAKlE,mBAAS,IAAI,GAAG,IAAI,WAAW,KAAK,GAAG;AACrC,oBAAQ,OAAO,MAAM,gBAAgB;AAAA,UACvC;AAAA,QACF;AACA,oCAAU;AAGV,aAAK,eAAe,CAAC;AACrB,YAAI,CAAC,KAAK,YAAY;AACpB,iCAAQ,MAAM,GAAG,OAAO,YAAY,UAAU,GAAG;AACjD,eAAK,aAAa;AAAA,QACpB;AAAA,MACF;AAAA,IACF,WAES,KAAK,QAAQ,IAAI,SAAS,KAAK;AAEtC,YAAM,KAAK,SAAS;AAEpB,UAAI,QAAQ,MAAM,OAAO;AACvB,gBAAQ,MAAM,WAAW,KAAK;AAAA,MAChC;AACA,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAAA,EACF;AACF;AAWO,SAAS,iBACd,OACA,UAA6B,CAAC,GACb;AACjB,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,EAAE,UAAU,gBAAW,IAAI;AACjC,UAAM,OAAO,iBAAiB,OAAO;AAGrC,QAAI,KAAK,cAAc,QAAQ,OAAO,OAAO;AAC3C,6BAAQ;AAAA,QACN,GAAG,OAAO,YAAY,QAAQ,cAAc,oBAAoB;AAAA,MAClE;AAAA,IACF;AAIA,QAAI,QAAQ,MAAM,OAAO;AACvB,2BAAAA,QAAS,mBAAmB,QAAQ,KAAK;AACzC,cAAQ,MAAM,WAAW,IAAI;AAE7B,YAAM,kBAAkB,sBAAsB,MAAM,OAAO,OAAO;AAClE,cAAQ,MAAM,GAAG,YAAY,eAAe;AAG5C,YAAM,GAAG,QAAQ,MAAM;AACrB,YAAI,QAAQ,MAAM,OAAO;AACvB,kBAAQ,MAAM,WAAW,KAAK;AAC9B,kBAAQ,MAAM,eAAe,YAAY,eAAe;AAAA,QAC1D;AAAA,MACF,CAAC;AAAA,IACH;AAGA,QAAI,MAAM,QAAQ;AAChB,YAAM,OAAO,GAAG,QAAQ,UAAQ;AAC9B,cAAM,OAAO,KAAK,SAAS;AAG3B,aAAK,iBAAiB;AAGtB,YAAI,QAAQ,gBAAgB,CAAC,QAAQ,aAAa,MAAM,QAAQ,GAAG;AAEjE,iBAAO;AAAA,QACT;AAEA,YAAI,KAAK,SAAS;AAChB,mCAAM,IAAI;AAAA,QACZ,OAAO;AAEL,eAAK,aAAa,KAAK,IAAI;AAI3B,gBAAM,QAAQ,KAAK,aAAa,KAAK,EAAE,EAAE,MAAM,IAAI;AACnD,cAAI,MAAM,SAAS,KAAM;AACvB,iBAAK,eAAe,CAAC,MAAM,MAAM,IAAK,EAAE,KAAK,IAAI,CAAC;AAAA,UACpD;AAAA,QACF;AACA,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAGA,QAAI,MAAM,QAAQ;AAChB,YAAM,OAAO,GAAG,QAAQ,UAAQ;AAC9B,cAAM,OAAO,KAAK,SAAS;AAG3B,aAAK,iBAAiB;AAGtB,YAAI,QAAQ,gBAAgB,CAAC,QAAQ,aAAa,MAAM,QAAQ,GAAG;AAEjE,iBAAO;AAAA,QACT;AAEA,YAAI,KAAK,SAAS;AAChB,kBAAQ,OAAO,MAAM,IAAI;AAAA,QAC3B,OAAO;AACL,eAAK,aAAa,KAAK,IAAI;AAAA,QAC7B;AACA,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAEA,UAAM,GAAG,QAAQ,UAAQ;AAEvB,UAAI,QAAQ,MAAM,OAAO;AACvB,gBAAQ,MAAM,WAAW,KAAK;AAAA,MAChC;AAGA,UAAI,YAAY,QAAQ;AACxB,UAAI,QAAQ,kBAAkB;AAC5B,cAAM,aAAa,QAAQ;AAAA,UACzB;AAAA,UACA,KAAK;AAAA,UACL,KAAK;AAAA,QACP;AACA,YAAI,eAAe,QAAW;AAC5B,sBAAY;AAAA,QACd;AAAA,MACF;AAEA,UAAI,KAAK,YAAY;AACnB,YAAI,cAAc,GAAG;AACnB,iCAAQ,eAAe,GAAG,OAAO,YAAY;AAAA,QAC/C,OAAO;AACL,iCAAQ,YAAY,GAAG,OAAO,SAAS;AAEvC,cAAI,KAAK,aAAa,SAAS,KAAK,CAAC,KAAK,SAAS;AACjD,oBAAQ,IAAI,kBAAkB;AAC9B,iBAAK,aAAa,QAAQ,UAAQ;AAChC,uCAAM,IAAI;AAAA,YACZ,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,cAAQ,SAAS;AAAA,IACnB,CAAC;AAED,UAAM,GAAG,SAAS,WAAS;AAEzB,UAAI,QAAQ,MAAM,OAAO;AACvB,gBAAQ,MAAM,WAAW,KAAK;AAAA,MAChC;AAEA,UAAI,KAAK,YAAY;AACnB,+BAAQ,YAAY,GAAG,OAAO,QAAQ;AAAA,MACxC;AACA,aAAO,KAAK;AAAA,IACd,CAAC;AAAA,EACH,CAAC;AACH;AAQA,eAAsB,YACpB,SACA,OAAiB,CAAC,GAClB,UAA4C,CAAC,GAC5B;AACjB,QAAM;AAAA,IACJ,UAAU;AAAA,IACV,aAAa;AAAA,IACb,aAAa;AAAA,IACb,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,YAAQ,iCAAM,SAAS,MAAM;AAAA,IACjC,OAAO,CAAC,WAAW,QAAQ,MAAM;AAAA,IACjC,GAAG;AAAA,EACL,CAAC;AAED,SAAO,MAAM,iBAAiB,OAAO,EAAE,SAAS,YAAY,WAAW,CAAC;AAC1E;",
|
|
6
6
|
"names": ["readline"]
|
|
7
7
|
}
|