()
| 187 | } |
| 188 | |
| 189 | async function saveBannerToWidgetFile() { |
| 190 | const extracted = extractBannerFromSnippet( |
| 191 | codeDraftFromState(latestState), |
| 192 | latestState.bannerDraft, |
| 193 | ); |
| 194 | const draft = sanitizeSelfEditBanner(extracted); |
| 195 | const manualSaveWindowUntilMs = Date.now() + 2500; |
| 196 | if (manualSaveWindowUntilMs > suppressHsrModalUntilMs) { |
| 197 | suppressHsrModalUntilMs = manualSaveWindowUntilMs; |
| 198 | } |
| 199 | |
| 200 | try { |
| 201 | const result = rewriteWidgetViewBanner(widgetViewModuleUrl, draft); |
| 202 | let reloaded = false; |
| 203 | if (app.hotReload) { |
| 204 | if (!app.hotReload.isRunning()) await app.hotReload.start(); |
| 205 | reloaded = await app.hotReload.reloadNow(); |
| 206 | } |
| 207 | |
| 208 | const now = Date.now(); |
| 209 | updateState((prev) => { |
| 210 | const nextSaveCount = prev.saveCount + 1; |
| 211 | const presentation = buildSavePresentation({ |
| 212 | changed: result.changed, |
| 213 | reloaded, |
| 214 | banner: result.banner, |
| 215 | saveCount: nextSaveCount, |
| 216 | nowMs: now, |
| 217 | }); |
| 218 | if (presentation.modal) suppressHsrModalUntilMs = now + 1200; |
| 219 | const nextSnippet = buildWidgetSnippet(result.banner); |
| 220 | const nextEditor = createCodeEditorState(nextSnippet, { |
| 221 | scrollTop: prev.codeScrollTop, |
| 222 | scrollLeft: prev.codeScrollLeft, |
| 223 | }); |
| 224 | |
| 225 | return Object.freeze({ |
| 226 | ...prev, |
| 227 | bannerDraft: result.banner, |
| 228 | codeDraft: nextSnippet, |
| 229 | codeLines: nextEditor.lines, |
| 230 | codeCursor: nextEditor.cursor, |
| 231 | codeSelection: nextEditor.selection, |
| 232 | codeScrollTop: nextEditor.scrollTop, |
| 233 | codeScrollLeft: nextEditor.scrollLeft, |
| 234 | saveCount: nextSaveCount, |
| 235 | selfEditStatus: Object.freeze(presentation.status), |
| 236 | feedbackModal: presentation.modal ?? closeModalState(), |
| 237 | activityFeed: appendActivityFeed( |
| 238 | prev.activityFeed, |
| 239 | presentation.activity, |
| 240 | ACTIVITY_FEED_LIMIT, |
| 241 | ), |
| 242 | }); |
| 243 | }); |
| 244 | } catch (error) { |
| 245 | const detail = error instanceof Error ? error.message : String(error); |
| 246 | updateState((prev) => |
no test coverage detected