Enable TypeScript strict mode across frontend, electron, and server#3388
Closed
jcfurey wants to merge 47 commits into
Closed
Enable TypeScript strict mode across frontend, electron, and server#3388jcfurey wants to merge 47 commits into
jcfurey wants to merge 47 commits into
Conversation
Security: - zip-slip guard in archive extraction (sanitize entry paths) - REMOTE control/API auth gate (require authenticated connection when a password is set) - harden WebRTC host window (deny navigation/new windows) - make export window contextIsolation explicit Correctness: - readExifData always resolves (fixes IPC hang) - save() queues concurrent saves instead of dropping them - requestMain registers listener before send; resolves when bridge absent - companion servers recreate listenable instances on restart; clear state on close - requestToMain uses a single shared dispatcher (no per-request global listener) - release thumbnail generation lock on timeout - single-pass now-playing token replacement - close fs.watch before re-watching downloads - per-process UUID fallback for machine id - order-independent deep compare in checkIfMatching - log previously-empty catches - normalize CRLF on CSV import Build/process: - add .nvmrc, engines field, and a PR CI workflow (build gate; format/svelte report-only) Verified: electron tsc type-check and production build pass.
- tmp -> ^0.2.7 (+ override) clears tmp path-traversal High across direct/grandiose/electron-builder - fast-xml-parser 5.4.1 -> ^5.8.0 (un-pinned) clears entity-expansion/builder-injection High - overrides shell-quote ^1.8.4 eliminates the critical svelte-inspector/open-in-editor/shell-quote chain - npm-run-all -> npm-run-all2@^9 (maintained drop-in) npm audit: 27 -> 21 (criticals 3 -> 0, highs 10 -> 7). Verified: electron tsc type-check and production build pass.
…or in audit docs - package-lock.json updated to match the dependency security fixes (tmp, fast-xml-parser, shell-quote override, npm-run-all2) - Correct an earlier audit error: package-lock.json IS committed/tracked; the .gitignore entry is a commented-out (inactive) line, not an active ignore rule. The 'no reproducible builds' finding is withdrawn. - ci.yml now installs with 'npm ci' (lockfile verified in sync via npm ci --dry-run)
- electron ^37.10.3 -> ^40.10.3; electron-builder ^26.15.2, electron-updater ^6.8.9 - better-sqlite3 -> ^12.10.0 (prebuilt binary available for Electron 40 ABI) - engines.node >= 22.12.0 (Electron 40 requirement); playwright CI node 20 -> 22 Stopped at 40 (not 42): Electron 41/42 ship V8 14 which removed v8::External::Value()/New(); better-sqlite3 12.10.0 fails to source-compile against it and has no prebuild for those ABIs. 40.10.3 is > 39.8.4 so it clears all flagged electron advisories. Verified: npm audit no longer flags electron (27->20 total, criticals 0, highs 7->6); electron tsc type-check passes; production build passes; app launches and fully renders under xvfb (screenshot confirmed). The single Playwright E2E test fails only on a stale welcome-popup selector, unrelated to Electron (and disabled in CI).
…on 40 The single E2E test had drifted from the UI and was failing on stale selectors: - pick the main window by URL (index.html) instead of firstWindow() (could be the splash) - drive the consolidated Initialize.svelte welcome popup (language dropdown, data-location folder picker, 'Get started!') instead of the old 3-step flow - guard the setup popup + onboarding guide so the test is idempotent (passes whether or not user data already exists) - group labels use data-title now -> select by text - save via Ctrl+S (the right-click 'Save' menu became 'Quick search') Verified passing under xvfb on both a fresh profile and an already-initialized one. Note: the test's FS_MOCK_STORE_PATH env var is not honored by the app, so state isn't isolated (harmless in fresh CI; noted as a follow-up).
…t RCE High) Pulls a patched serialize-javascript (7.0.5), clearing the High (GHSA-5c6j-r48x-rmvq) plus a @rollup/plugin-terser moderate. Zero-risk: the only consumer (config/building/rollup.config.mjs) isn't referenced by any build script (the active build uses Vite + tsc), and the terser() plugin API is unchanged (peer rollup ^4). npm audit: 20 -> 18 (criticals 0, highs 6 -> 5). Build verified.
…oderate) v8+ is ESM-only, but no dynamic-import conversion was needed: Electron 40 bundles Node >=22.12 which supports require() of ESM (music-metadata exposes a module-sync export condition and has no top-level await), so the existing static imports work. Only code change: v11 returns IPicture.data as Uint8Array instead of Buffer, so cover-art handling wraps it with Buffer.from(). Verified: electron tsc passes; svelte-check unchanged (ICommonTagsResult still exported); production build passes; E2E smoke test passes (decisive, since music-metadata is require()d at startup via responsesMain.ts). npm audit: 18 -> 16 (criticals 0, highs 5 -> 4).
…luded from PR diff and line counts
…ual diffs); keep linguist-generated
…ser (S4)
The variable-expression and number-input calculators used new Function("return "+x)(),
which executes arbitrary JS from user/network-reachable input. Replaced all four call
sites with evaluateExpression() — an arithmetic-only recursive-descent parser (numbers,
+ - * / % **, unary +/-, parentheses) that throws on any identifier/call/property access.
Verified: 19/19 unit checks (valid math computes correctly; alert(1), Math.PI, x=5,
__proto__, etc. all throw); production build passes.
…lint-plugin-svelte - Replace the three legacy eslintrc files with one flat config (config/linting/eslint.config.mjs). - eslint 8 (EOL) -> 9; @typescript-eslint 5 -> typescript-eslint 8; eslint-config-prettier 8 -> 10; eslint-plugin-jsdoc 39 -> 50; swap deprecated eslint-plugin-svelte3 -> eslint-plugin-svelte 3 (+ svelte-eslint-parser, supports Svelte 3); drop unused eslint-plugin-prefer-arrow. - Consolidate lint scripts into a single 'lint:eslint' (flat config scopes electron/frontend/svelte; --ext is removed in eslint 9). - Rule set kept behaviour-faithful: map removed v8 rules (ban-types -> no-restricted-types, no-empty-interface -> no-empty-object-type, no-var-requires -> no-require-imports, id-blacklist -> id-denylist), drop removed 'off' formatting rules, and turn off v8's newly-recommended promise/type rules to match the old config's intent. eslint:recommended intentionally not added (the old config never extended it). Verified: flat config loads and lints electron, frontend TS, and Svelte 3 components with no config/parsing errors; findings match the old rule set (pre-existing, mostly auto-fixable). Build passes; lockfile npm ci-verified. The old eslintrc files are kept (superseded; removable). The legacy config files (eslint.electron.json/eslint.frontend.json/eslint.svelte.js) are now unused.
eslint.electron.json / eslint.frontend.json / eslint.svelte.js are no longer referenced (replaced by config/linting/eslint.config.mjs in the ESLint 9 migration).
Mechanical autofixes across 291 files (prefer-const, consistent-type-imports, dot-notation, object-shorthand, no-var, etc.) from 'npm run lint', plus Prettier formatting on the touched files. Kept as a separate commit from the config migration. Verified: electron tsc passes; production build passes; svelte-check improved (199 -> 186 errors, no new ones); E2E smoke test passes. The remaining ~604 non-fixable findings (no-shadow / no-console / no-unused-vars debt) are left for follow-up.
Toolchain:
- svelte 3 -> 5, vite 4 -> 8, @sveltejs/vite-plugin-svelte 2 -> 7, svelte-check 2 -> 4,
typescript 4.9 -> 5.9, @tsconfig/svelte 2 -> 5.
- Replace svelte-preprocess with vitePreprocess (svelte.config + both vite configs).
- Drop svelte-inspector fork + rollup-plugin-svelte (Svelte-3-only, used only by the
unused rollup.config.mjs).
Code changes (Svelte 5 / Vite 8 / TS 5 compatibility):
- Component instantiation: new App({target}) -> mount(App, {target}) (frontend + 5 server entries).
- Top.svelte: <script type="ts"> -> <script lang="ts"> (vitePreprocess needs lang).
- Connection.svelte: rename {@const connections} (Svelte 5 disallows shadowing a store name in a store subscription).
- Server type-only imports marked (Rolldown rejects type-as-value): Writable, ReceiverKey,
Deep*/Inferred/Nested, AutosizeTypes, StageItem/StageLayout.
- bonjour.ts: bonjour-service 1.4 exports Service as a value -> InstanceType<typeof Service> (TS 5).
- Raise the E2E test timeout (the flow is slightly slower under Svelte 5).
Status: full production build passes (frontend + servers + electron); the app launches and the
E2E user flow completes (verified via screenshot). KNOWN REMAINING: the electron process does not
exit cleanly after the test (worker-teardown hang) — needs investigation; svelte-check (v4) reports
~584 issues (mostly Svelte 5 deprecations/strictness) for a follow-up cleanup; full feature QA pending.
…umbrella) @tsconfig/svelte v5 turns on "strict" (incl. noImplicitAny), which the project intentionally kept off (it opts into only strictNullChecks/strictFunctionTypes/ noImplicitThis). Restoring strict:false drops svelte-check from 584 -> 78 errors (below the pre-migration ~186 baseline). Type-check only; the esbuild-based build is unaffected.
…stale build prereqs Adds a comprehensive build/test/packaging guide derived from the CI workflows, covering all three OSes (toolchains, Node 22.12, Python — incl. the macOS 3.11 node-gyp caveat, dev run, production build, the E2E test incl. the Linux xvfb wrapper, lint/format, and packaging/release + signing env vars). Also reconciles the README and CLAUDE.md: Linux needs libfontconfig1-dev + uuid-dev + libltc-dev (not just libfontconfig1-dev), notes Node 22.12+, and links to BUILDING.md.
…environment Pins the OS toolchain + Node 22.12 + Python + the native-build system libs (libfontconfig1-dev/uuid-dev/libltc-dev) + xvfb, installs deps (npm ci when a lockfile exists, else npm install) and runs the production build. Documented in BUILDING.md with usage (build/pack/test) and the lockfile traceability caveat. Note: targets Linux only (Electron builds per-platform). Not container-build-tested here (no Docker daemon in this env), but mirrors the verified CI/local build steps.
package-lock.json is already committed and in sync; switch build.yml, playwright.yml, and release.yml (Windows/Linux/macOS) from npm install to npm ci for reproducible, deterministic installs. Verified the lockfile records all platforms' optional native binaries (rollup/rolldown win32/darwin/linux with os/cpu constraints), so npm ci picks the right one per platform — and a clean npm ci (incl. native rebuild) passes on Linux. Also: add the missing uuid-dev/libltc-dev to playwright.yml's apt step (needed for the native rebuild), and replace the obsolete @rollup/rollup-x-gnu note in .gitignore (that npm bug was fixed in npm 10).
…oing forward Svelte 5 warns on self-closing non-void HTML elements (<div ... /> etc.). Converted all 204 occurrences across frontend + server components to explicit close tags (<div ...></div>) using eslint-plugin-svelte's autofixable svelte/html-self-closing rule (AST-safe), then prettier-formatted. Also enabled that rule in the project ESLint config (frontend) so it can't regress. Verified: full build passes (frontend + servers + electron); svelte-check warnings 299 -> 144 (the ~155 self-closing warnings cleared; 78 errors unchanged); E2E smoke test passes.
… labels, aria-selected)
- img alt="" on decorative output media / preview thumbnails / custom action icons (3)
- aria-label on icon-only inc/dec buttons in MaterialNumberInput + MaterialRadialPicker (4)
- aria-selected={false} on the non-selectable 'add new' dropdown option (2)
These are universally-correct improvements with no behaviour change. Build passes;
svelte-check warnings 144 -> 135; E2E passes.
The remaining a11y warnings are judgment-/risk-heavy and out of scope here (see PR notes):
~90 interactive <div> elements would need role+tabindex+keyboard handlers (changes
operator-UI tab order/key handling, which the build deliberately suppresses via onwarn),
plus intentional autofocus and structural floating-label cases.
The autofocus inputs/textareas are prop-driven (a caller opts in to focus a field when a dialog/field appears) — intentional operator UX. Marked with <!-- svelte-ignore a11y_autofocus --> rather than removing it. svelte-check warnings 135 -> 127.
The two .pickColor gradient swatches already had tabindex/aria-label but no keyboard
handler; added on:keydown={triggerClickOnEnterSpace} (reuses the existing click via the
shared helper, no new tab stops). svelte-check warnings 127 -> 125.
Inventories the remaining ~125 svelte-check a11y warnings (by category + component area), documents the fix patterns (using the existing clickable.ts helpers), the real risks (tab-order changes, key conflicts, manual-QA-only verification), a phased plan, and the policy decisions to make first (enforce a11y? remove the onwarn suppression? i18n aria-labels?).
jcfurey
pushed a commit
to jcfurey/freeshow
that referenced
this pull request
Jun 16, 2026
The committed public/index.html referenced the production bundle (./build/bundle.js), which only exists after `vite build` — a setProductionHTML() artifact that cleanBuilds.js never reverted before commit. Restore the dev source entry (/src/frontend/main.ts) to match upstream; postBuild.js still swaps in the bundle tags for production, cleanBuilds.js reverts. Fixes a broken `npm start` dev server. https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
…ripture) Now that the vitest harness is in place, cover three dependency-free modules that are easy to get subtly wrong: - frontend/utils/expression.ts — the security-critical safe arithmetic parser: math correctness (precedence, associativity, unary, e-notation) and, most importantly, that it REJECTS identifiers / calls / property access, which is what makes it a safe replacement for new Function(). - frontend/components/helpers/color.ts — hex/rgb/hsl conversions, contrast, fade, and round-trips. - common/scripture/sanitizeVerseText.ts — <br>/<q>/nbsp/whitespace handling. 52 new tests (70 total with the existing syncLedger suite); all pass. svelte-check unchanged (the same 78 pre-existing migration errors). Updated CLAUDE.md to document the vitest unit-test layer and how to run a single file. https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
…elpers Four more dependency-free modules: - frontend/utils/chordTranspose.ts — sharp/flat preference by direction, octave wrap, slash chords, unicode accidentals, and leaving section labels (e.g. [Chorus], [Verse 1]) untouched. - frontend/components/helpers/bytes.ts — unit boundaries and the decimals arg. - frontend/components/helpers/style.ts — style-string parsing, unit stripping, and transform -> filter expansion. - frontend/components/helpers/cropping.ts — crop clamping/scaling, pan limits, center, and the generated clip-path / ppt zoom geometry. 36 new tests (106 total); all pass. svelte-check unchanged (78 pre-existing). https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
Three more import-clean modules: - frontend/components/helpers/mover.ts — the drag-reorder array logic (getIndexes, addToPos, and mover incl. the position adjustment when moving items forward past the gap they leave). - frontend/utils/clickable.ts — Enter/Space activation handlers, incl. the guards for inputs/textareas/editable elements and the Space-in-slide case. - frontend/utils/languageData.ts — a data-integrity invariant: every language has a non-empty browser-locale mapping and a flag, with no stray keys. 19 new tests (125 total); all pass. svelte-check unchanged (78 pre-existing). Note: array.ts/time.ts remain untested — they transitively import stores.ts -> showActions.ts -> pdfjs-dist, which needs DOMMatrix at import time and so won't load under vitest's node environment. https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
- electron/utils/helpers.ts — clone (deep, reference-independent), the order-normalized checkIfMatching used by cloud sync (key-order-insensitive for objects but order-sensitive for arrays), and wait. - frontend/components/helpers/fonts.ts — getFontName quoting rules. - frontend/utils/request.ts — renderer IPC dispatch helpers (send fans out per channel; receive routes a message to its channel handler), via a window.api mock. 14 new tests (139 total); all pass. svelte-check unchanged (78 pre-existing). Test files are excluded from the electron build via the base tsconfig's **/*.test.ts exclude (the prod tsconfig is generated from it by preBuild.js). https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
These two high-traffic modules looked untestable because array.ts imports
utils/language — a hub that transitively drags in stores.ts -> svelte components
and browser globals. Solved surgically with module mocking rather than global
env hacks (which cascaded into the whole UI):
- array.ts: vi.mock("../../utils/language") cuts the chain. Covers
removeDuplicates, keysToID, removeValues/removeDeleted, removeDuplicateValues,
changeValues, clone, areObjectsEqual, moveToPos, the sorts, getChangedKeys and
rangeSelect (ctrl/meta/shift selection logic).
- time.ts imports cleanly (stores.ts only creates writables). Covers
secondsToTime, joinTime/joinTimeBig, padString/addZero, splitDate,
combineDateAndTime/changeTime, getWeekday/getMonthName (English fallback and a
provided dictionary), timeAgo and getTimeFromInterval.
40 new tests (179 total); all pass. svelte-check unchanged (78 pre-existing).
https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
The converters build a ShowObj and call setTempShows inside a setTimeout (no return value) and transitively import the whole app. Established a reusable harness: mock the show-building collaborators (ShowObj, array/clone, setShow, show, itemHelpers, importHelpers) while stores stay real, drive the converter with fake timers, and capture setTempShows to assert on the parsed output. - chordpro.ts: metadata directives + aliases (t/ccli/f/su), inline chord position extraction, # comment -> layout notes, and section splitting across markers. - csv.ts: parseCSVLine quoted / triple-quoted / unquoted fields, one slide per row and one item per field, empty-line dropping, and CRLF normalization. 11 new tests (190 total); all pass. svelte-check unchanged (78 pre-existing). https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
More option-1 (no new deps) converters: - txt.ts exported helpers: trimNameFromString (name extraction incl. label-skip, punctuation/html stripping, length truncation), similarity (case-insensitive edit-distance ratio), and findGroupMatch (group id / custom display name / dictionary-translation fallback). The heavy convertText pipeline is left out as too intricate to unit-test meaningfully. - songbeamer.ts full pipeline (runs synchronously): #-prefixed metadata parsing incl. CCLI digit extraction, title -> name with file-name fallback, UTF-8 BOM stripping, and grouped slides with their lyric lines. 17 new tests (207 total); all pass. svelte-check unchanged (78 pre-existing). https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
XML converters route through a real DOMParser (xml2json / getElementsByTagName), which node lacks. Added jsdom as a dev dependency and opt the relevant test files into it per-file via `// @vitest-environment jsdom` (no global config change). Tried happy-dom first but it mis-iterates element attributes (empty nodeName/nodeValue); jsdom is spec-faithful. - xml.ts: xml2json element/text parsing, @-prefixed attributes, repeated-element -> array collapsing, and XML-declaration header stripping. - opensong.ts: metadata via DOMParser, [V] tag -> verse global group, "." chord lines attached to the following lyric line, and ";" comments captured as slide notes. 8 new tests (215 total); all pass. svelte-check unchanged (78 pre-existing). https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
More XML converters on the jsdom unlock: - openlp.ts (OpenLyrics): metadata (title/author/CCLI/copyright), verses split on <br/>, V/C group-name mapping, verseOrder-driven layout order, and inline [chord] position extraction. - zefaniaBible.ts: parses the Zefania XML bible (books/chapters/verses) and registers it in the scriptures store; file-name fallback when biblename is absent. 7 new tests (222 total); all pass. svelte-check unchanged (78 pre-existing). https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
ProPresenter is the most involved converter; covered both import shapes: - JSON: convertJSONToSlides (verses -> slides, group mapping, verse_order layout, metadata) and convertJSONBundleToSlides (<p>/<br> lyrics). - XML (.pro4): the real decode pipeline base64 -> decodeBase64 -> RTFToText/decodeHex -> splitTextToLines. Fixtures build base64-encoded RTF in-test and assert the decoded lyrics, CCLI metadata from document attributes, \par -> newline, and the PlainText fallback (paragraph splitting). 8 new tests (230 total); all pass. svelte-check unchanged (78 pre-existing). https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
… EasySlides, MediaShout) Rounds out converter coverage with the jsdom + harness pattern: - quelea.ts: sections -> slides, metadata, group mapping. - osisBible.ts / bebliaBible.ts: XML bible -> books/chapters/verses + scripture-store registration (named books to skip the translate prompt). - verseview.ts: CDATA lyrics split on <slide>/<br>. - easyslides.ts: Contents -> slides with [group] labels and SongNumber metadata. - mediashout.ts: MediaShout5 Cues -> slides from Content Elements. 12 new tests (242 total); all pass. svelte-check unchanged (78 pre-existing). https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
Two more song converters (both JSON/object-based, no DOM needed): - videopsalm.ts: exercises the malformed-JSON repair pipeline (unquoted keys -> valid JSON), verse <br> splitting, inline [chord] extraction, and metadata. - softprojector.ts: pre-parsed song object -> slides (first line of each block is the group label), with metadata. 5 new tests (247 total); all pass. svelte-check unchanged (78 pre-existing). https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
Two non-song converters: - calendar.ts: ICS/iCal parsing (BEGIN/END nesting via convertToJSON) into stored events, including RRULE -> repeatData mapping. - project.ts: importProject distributes overlays/effects/actions/media into their stores and creates the shows + project through history. 4 new tests (251 total); all pass. svelte-check unchanged (78 pre-existing). https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
… any, props) - MaterialButton.svelte: type the `button` element + event/id params; drop the unused `translate` import. - VirtualList.svelte: give `itemHeight` a default so it's an optional prop — callers already relied on the existing `|| 30` fallback (behavior unchanged). - AudioFilter.svelte: drop unused `translateText`; Array.from(magResp) before .map() — Float32Array.map coerced the SVG-path strings to NaN, a latent runtime bug now fixed. - ScriptureContentTablet.svelte: mark the unused `source` param. svelte-check: 78 -> 62 errors, no new ones. https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
PDF export iterates project items that may be shows, sections, or media, with display fields (data, metaDisplay) added at runtime in getRefs() — but they were typed as plain Show. Introduced an ExportShow augmented type for `shows`/`renderedShows` and the page-count helper, guarded `show.id` indexing with `|| ""`, and cast the legacy `chord.chord` fallback. No behavior change. svelte-check: 62 -> 23 errors, no new ones. https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
…eck now 0) - Null/undefined guards: ContextItem (|| false), ListView (?.length ?? 0), ChooseStyle (type/outputs defaults). - Number coercion for TemplateStyle's MaterialNumberInput values. - dataArrays now infers Uint8Array<ArrayBuffer> (dropped the explicit Uint8Array[] annotation) in AudioPreview/Visualizer. - Optional props: SlideItems.itemElem and OutputTransition.transition default to undefined so callers needn't pass them. - Type extensions: API_output_style gains outputStyle/styleOutputs; getCameraStream accepts an options arg. - Casts for legacy/loose access: EditboxLines redo history, Lyrics line/text ids, Timer alignX, Media thumbnailPath, ChooseEmitter template value, stage Slide item. - @ts-ignore for the plain-JS tablet VirtualList import (types unresolved under the server tsconfig). svelte-check: 23 -> 0 errors (78 -> 0 across the whole effort). Unit tests still green (251). No behavior changes. https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
…red) Flip strict:true in src/frontend/tsconfig.json, restoring the umbrella the Svelte 5 migration had disabled. With the 78 prior type errors already cleared, the only strict sub-flag with real cost is noImplicitAny (~508 errors, mostly untyped params + index access) — kept off as a separate migration, matching the project's prior stance. The newly active flags (strictBindCallApply, strictPropertyInitialization, useUnknownInCatchVariables, alwaysStrict) needed just one fix: - ImportScripture.svelte: catch (err) is now `unknown`; String(err) before assigning to the string error field (preserves the displayed message). svelte-check: 0 errors with strict:true. Unit tests green (251). https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
…63 remaining) Working toward full strict (noImplicitAny enabled). This batch: - CustomInput.svelte: typed the `value` prop + a couple of params / index casts (cleared the 46-error cascade from one untyped variable). - 199 untyped function/callback params across 86 files annotated `: any` (matching the codebase's existing style), applied via a position-driven script verified against each reported identifier (0 mismatches). svelte-check noImplicitAny: 508 -> 263. Unit tests green (251); Prettier clean. Remaining: ~203 index-access, 34 variable, 14 binding, 7 revealed null-checks. https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
… fixed, 42 left) Continued noImplicitAny migration via position-driven scripts (each verified against the reported identifier; 0 mismatches): - 187 object index accesses wrapped as (obj as any)[key], with a leading ';' ASI guard where the cast starts a statement (the codebase is no-semicolons). - 11 untyped `let` declarations annotated `: any`, clearing their cascading usages. svelte-check noImplicitAny: 263 -> 42. Unit tests green (251); Prettier applied. Remaining 42: 14 destructuring bindings, 16 member/array index, 7 revealed null-checks, a few misc — to finish manually. https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
…ck 0 errors Final manual batch (42 + 7 follow-ons): - Destructuring params typed `: any` (Calendar/Day getEventIcon, NDIStreams, EditboxLines cutInTwo, ChooseCamera, DeleteDuplicatedShows). - Member/call/array index casts the scripts skipped (ChooseEmitter, MidiValues, Emitters, EditboxLines, edit+stage BoxStyle, ItemStyle, SlideFilters, Conditions, SelectTemplate, Variable, Variables), with `;` ASI guards on statement-leading casts. - SelectElem: `let layout: any` clears its revealed null-checks; newly-revealed params typed (audioId, DisplayDuration updater). - EditValues: guard `extension || ""`. YouTubePlayer: @ts-ignore (youtube-player ships no type declarations). svelte-check: 508 -> 0 with strict:true (noImplicitAny enabled). Unit tests green (251); Prettier clean. Full TypeScript strict mode is now on with zero errors. https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
The electron side already opted into noImplicitAny / strictNullChecks / strictFunctionTypes / noImplicitThis, but not the full strict umbrella. Flip strict:true; the only new errors were 4 catch variables now typed `unknown` (useUnknownInCatchVariables) — cast `(error as Error).message` in OAuth2Helper, NdiReceiver and pptToShow (behavior unchanged). tsc --noEmit (electron): 0 errors. Unit tests green (251); Prettier clean. Both the frontend and electron tsconfigs are now on full strict with zero type errors. https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
src/server/tsconfig.json was already strict:true, but nothing ran tsc against it (the companion apps ship via esbuild and svelte-check uses the frontend config), so it had 5 latent errors. `tsc -p tsconfig.server.json` is now clean: - HtmlSlideHelper: import `_store` (aliased as `stores`) instead of the non-existent `stores` export, and guard the optional `_store.SHOWS/SETTINGS` with `?.`. - audioStream: type bufferQueue channels as Float32Array<ArrayBuffer> so copyToChannel accepts them (TS 5.7 ArrayBuffer typing). - Blackmagic (electron files pulled in transitively, where macadam types resolve differently under the server config): cast getDeviceConfig result and the onFramePlayed access. Electron tsc unaffected (still 0). All three TS projects now pass full strict with 0 errors: svelte-check (frontend), tsc (electron), tsc (server). Unit tests green (251); Prettier clean. https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
ef5dac8 to
5a3b6cb
Compare
Collaborator
|
For what I can see it just adds |
jcfurey
pushed a commit
to jcfurey/freeshow
that referenced
this pull request
Jun 16, 2026
…shback HTML-fetched all 8 upstream PR pages (2026-06-16): - CLOSED by vassbo: ChurchApps#3386 (Svelte 5 migration), ChurchApps#3387 (tests "not a benefit"), ChurchApps#3388 (strict types ":any churn"), ChurchApps#3389 (build/transition/regressions, silent). - OPEN with pushback: ChurchApps#3385 (safe-eval "fine to use new Function, local app"), ChurchApps#3390 ("what's the improvement? remove Rebuild button"), ChurchApps#3391 ("not necessary"). - OPEN no comment: ChurchApps#3384 (security/deps). Pattern: maintainer declining most modernization as unnecessary for a local desktop app. Closing ChurchApps#3386 makes the transition fix moot upstream for now. https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
jcfurey
pushed a commit
to jcfurey/freeshow
that referenced
this pull request
Jun 16, 2026
…#3385/ChurchApps#3391 closed, ChurchApps#3384 sole open Current upstream state (2026-06-16 ~18:35, via HTML fetch): - ChurchApps#3390 MERGED ("Nice, great!") — first modernization PR landed. - ChurchApps#3384 OPEN & ready, awaiting maintainer (sole live PR). - ChurchApps#3385 CLOSED (jcfurey conceded the safe-eval; ESLint-9 set aside). - ChurchApps#3391 CLOSED by vassbo (declined as unnecessary). - ChurchApps#3386 CLOSED/parked — standalone migration ready, opens after ChurchApps#3384. - ChurchApps#3387/ChurchApps#3388/ChurchApps#3389 closed. https://claude.ai/code/session_01GnucxHgJuqNxYHbeHonfRm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🔗 Stacked on #3387 (vitest suite). This PR clears the ~76 Svelte 5 migration type errors deferred from PR3/PR4 and completes strict mode.
Builds on the Svelte 5 migration to re-enable and complete TypeScript strict mode.
Resolve the remaining Svelte 5 migration type errors (svelte-check → 0)
Re-enable strict mode, then work through noImplicitAny in stages (type untyped params, cast index access, type variable declarations) until full strict passes
Enable full strict for the electron tsconfig; make the already-strict server tsconfig type-check clean
Mostly type annotations and safe casts (+410 / −415), no runtime behavior change.
Verification: svelte-check (0 errors), electron tsc, and server tsc all clean.