@@ -6,6 +6,7 @@ import baseMiddleware from "../middlewares/base.js";
66import { getUi5DataDir } from "../../framework/utils.js" ;
77import * as frameworkCache from "@ui5/project/ui5Framework/cache" ;
88import CacheManager from "@ui5/project/build/cache/CacheManager" ;
9+ import prettyHrtime from "pretty-hrtime" ;
910
1011const cacheCommand = {
1112 command : "cache" ,
@@ -86,6 +87,64 @@ function padLabel(label) {
8687 return label . padEnd ( LABEL_WIDTH ) ;
8788}
8889
90+ const SPINNER_FRAMES = [ "⠋" , "⠙" , "⠹" , "⠸" , "⠼" , "⠴" , "⠦" , "⠧" , "⠇" , "⠏" ] ;
91+ const PROGRESS_DEBOUNCE_MS = 150 ;
92+ // Reserve enough columns for the fixed parts of the progress line so the path
93+ // never causes the line to wrap on a standard 80-column terminal.
94+ const PATH_MAX_COLS = 40 ;
95+
96+ /**
97+ * Build a progress handler for framework cache deletion.
98+ * Returns a function to pass as onProgress to cleanCache(), plus a finalise()
99+ * to call when deletion completes (clears the in-progress line).
100+ *
101+ * The line is written to stderr with \r so it overwrites itself on each tick,
102+ * producing a single updating line rather than a scrolling log.
103+ *
104+ * @param {string } label Short label shown on the progress line
105+ * @param {[number, number] } startHrtime process.hrtime() snapshot taken when deletion began
106+ * @param {function([number, number]): string } prettyHrtime Formatting function from the pretty-hrtime package
107+ * @returns {{onProgress: function(string): void, finalise: function(): void} }
108+ */
109+ function createProgressHandler ( label , startHrtime , prettyHrtime ) {
110+ let lastPrintMs = 0 ;
111+ let frameIndex = 0 ;
112+ let lastVisibleLen = 0 ;
113+
114+ function onProgress ( entryPath ) {
115+ const now = Date . now ( ) ;
116+ if ( now - lastPrintMs < PROGRESS_DEBOUNCE_MS ) return ;
117+ lastPrintMs = now ;
118+
119+ const elapsed = prettyHrtime ( process . hrtime ( startHrtime ) ) ;
120+ const spinner = SPINNER_FRAMES [ frameIndex % SPINNER_FRAMES . length ] ;
121+ frameIndex ++ ;
122+
123+ // Trim path so the whole line stays within 80 columns
124+ let displayPath = entryPath ;
125+ if ( displayPath . length > PATH_MAX_COLS ) {
126+ displayPath = "…" + displayPath . slice ( - ( PATH_MAX_COLS - 1 ) ) ;
127+ }
128+
129+ // Build visible text (no ANSI) first to get accurate length for overwrite padding
130+ const visibleText = ` ${ spinner } ${ label } ${ displayPath } ${ elapsed } ` ;
131+ // Then the styled version for actual output
132+ const styledText = ` ${ spinner } ${ label } ${ chalk . dim ( displayPath ) } ${ elapsed } ` ;
133+
134+ // Pad to cover any longer previous line, then overwrite in place
135+ const padded = styledText + " " . repeat ( Math . max ( 0 , lastVisibleLen - visibleText . length ) ) ;
136+ lastVisibleLen = visibleText . length ;
137+
138+ process . stderr . write ( `\r${ padded } ` ) ;
139+ }
140+
141+ function finalise ( ) {
142+ process . stderr . write ( `\r${ " " . repeat ( lastVisibleLen ) } \r` ) ;
143+ }
144+
145+ return { onProgress, finalise} ;
146+ }
147+
89148async function handleCache ( argv ) {
90149 // Resolve UI5 data directory — uses the same resolution chain as ui5 build/serve:
91150 // UI5_DATA_DIR env var → ui5DataDir config (~/.ui5rc) → default ~/.ui5
@@ -154,7 +213,16 @@ async function handleCache(argv) {
154213 }
155214
156215 // Perform the actual cleanup (orchestrate both domains)
157- const frameworkResult = await frameworkCache . cleanCache ( ui5DataDir ) ;
216+ let frameworkResult ;
217+ if ( frameworkInfo ) {
218+ const startHrtime = process . hrtime ( ) ;
219+ const { onProgress, finalise} = createProgressHandler ( LABEL_FRAMEWORK , startHrtime , prettyHrtime ) ;
220+ try {
221+ frameworkResult = await frameworkCache . cleanCache ( ui5DataDir , onProgress ) ;
222+ } finally {
223+ finalise ( ) ;
224+ }
225+ }
158226 const buildResult = await CacheManager . cleanCache ( ui5DataDir ) ;
159227
160228 process . stderr . write ( "\n" ) ;
0 commit comments