refactor(lib): stop exporting 23 symbols that never leave their module - #444
Merged
Conversation
Fixes no bug. Every one of these compiles, runs, and behaves exactly as before -- the only change is that a reader opening one of these modules now sees an interface that matches what the module actually promises. 23 declarations lose the `export` keyword. None are deleted: all 23 are called or referenced inside their own file, so the declaration stays and only its visibility narrows. The line drawn here: a type keeps `export` when it is directly the parameter type or the return type of an exported function, or the declared type of an exported constant -- a caller who builds the argument in a separate statement, or holds the result in a typed field, has to be able to name it. It loses `export` when it is only reachable inside such a type (a field of an options bag), or appears only in value positions internal to the module. A function loses `export` when every call to it is in its own file. 26 of the 49 candidates are kept on that basis. No renames, no reordering, no adjacent cleanup. `npm test` 565/565 unchanged, `npm run check` 637 files / 0 errors, `npm run build` clean. No Rust touched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
This fixes no bug. Nothing here changes behaviour, output, or performance. 23 declarations lose the
exportkeyword and keep everything else. The benefit is that a reader opening one of these modules sees an interface that reflects what the module actually promises, instead of one where two thirds of the surface is noise.npm test565/565 (unchanged from6b58cd5),npm run check637 files / 0 errors,npm run buildclean. No Rust touched.The starting list was right about references and wrong about what follows
The candidates came from a scan for
exported symbols insrc/lib/**/*.tswith no consumer outside their defining file — 49 of them, after setting aside 29 that onlyscripts/consumes. Re-checked here acrosssrc/,scripts/,src-tauri/, and the root config files: all 49 do have zero external references. That part held.What did not hold is the conclusion. The scan excluded the defining file from its own search, so "no external reference" was being read as "dead". Printing every in-file occurrence of all 49 settles it:
Every one of the 49 is used inside its own file. Not one is an orphan. So the delete bucket is empty, and the whole question is
export-removal versus keep.exportremoved, declaration keptThe line
A type keeps
exportwhen it is directly the parameter type or the return type of an exported function, or the declared type of an exported constant. That is the module's stated interface: a caller who builds the argument in a separate statement (const ctx: PdfExportContext = {…}) or holds the result in a typed field has to be able to name it, and no importer existing yet is not evidence that none should.A type loses
exportwhen it is only reachable inside such a type — a field of an options bag — or appears only in value positions internal to the module. Structural typing and inference cover those; a caller never has to write the name. A function losesexportwhen every call to it is in its own file.That rule decides all 49 without a tie-break, and re-exporting any of them later is a one-word change.
exportremoved (23)SUPPORTED_LANGUAGESstores/settings.svelte.tsSUPPORTED_LANGUAGE_CODESSUPPORTED_LANGUAGE_CODESstores/settings.svelte.tsisSupportedLanguageisSupportedLanguagestores/settings.svelte.ts:751, validating the persistedlanguagekeyloadPersistedSettingsstores/settings.svelte.ts:343,:423)installPersistedSettingsstores/settings.svelte.ts:435UpdatePhasestores/update.svelte.tsUpdateDialog.sveltecomparesupdateStore.phaseto string literals and never names the typeErrorSourcestores/update.svelte.tsEditorToolbarGrouputils/editorToolbar.tsEditorToolbarToolEDITOR_TOOLBAR_TOOLSutils/editorToolbar.tsgetEditorToolbarTools()andDEFAULT_EDITOR_TOOLBAR_ORDERKatexFamilyRuleutils/exportFonts.tsparseKatexFamilyRules, which is itself internalparseKatexFamilyRulesutils/exportFonts.ts:109, insidecollectUsedKatexFamiliescollectClassNamesutils/exportFonts.ts:106, samebytesToBase64utils/exportFonts.ts:247, insidefetchFontDataUrlsFrontMatterValueKindutils/frontMatter.tsFrontMatterFieldparseFrontMatterTagInpututils/frontMatter.tsisAbsoluteMarkdownPathutils/markdownLinks.ts:54MermaidRendererutils/mermaidPrint.tsPrintDiagramContext(which stays exported)OpenExportedFileLabelsutils/openExportedFile.tsOpenExportedFileDeps(which stays exported)PASTE_PROBE_CHARACTERutils/pasteContext.ts:122PasteContextTokenizerutils/pasteContext.tsPasteCaretContext(which stays exported)isCodeAtOffsetutils/pasteContext.ts:156TabFileActionIdutils/tabFileActions.tsTabFileAction(which stays exported)TITLEBAR_TOOLBAR_ACTIONSutils/titlebarToolbar.tsgetTitlebarToolbarActions()and the twoDEFAULT_TITLEBAR_TOOLBAR_*constantsKept exported (26)
24 of them are the vocabulary of a module's public interface — the shape a caller has to name to build an argument or hold a result:
ExternalChangeOutcomeresolveExternalChange, whichcreateDocumentSessionhands back (documentSession.svelte.ts:630)PersistedSettingcreateSettingsPersistence()EditorToolbarMoveapplyEditorToolbarMove, return ofgetEditorToolbar{Reorder,Adjacent}MoveExportHtmlResultexportAsHtmlPdfExportContextexportAsPdfExportDocumentInputbuildExportDocumentKatexFontFacefindKatexFontFacesPrintDiagramContextrenderDiagramsForPrintExportedFileFormataskToOpenExportedFileOpenExportedFileResultaskToOpenExportedFileOpenExportedFileDepsaskToOpenExportedFilePasteCaretContextshouldLinkifyPastedUrlPathIdentityisSameFilePathLineRangeparseSourceposLineRangeAnchorNodefindAnchorElementAnchorMatchfindAnchorElementRenderRichContentOptionsrenderRichContentTabFileActiongetTabFileActionsFileHistoryStateFileHistoryNavigationStatereplaceCurrentHistoryEntry,navigateFileHistoryFileHistoryNavigationResultgoBackInHistory,goForwardInHistoryTitlebarToolbarActiongetTitlebarToolbarActionsTitlebarToolbarMoveapplyTitlebarToolbarMove, return ofgetTitlebarToolbar{Reorder,Adjacent}MoveConfiguredTitlebarToolbarIdsgetConfiguredTitlebarToolbarIdsDefaultFontsDEFAULT_FONTS, whichSettings.sveltereadsPersistedSettingis the clearest of these.scripts/settingsPersistence.test.ts:100needs that type and cannot import it, so it writesReturnType<typeof createSettingsPersistence>[number]instead. The export is doing work even with noimportnaming it.The 26th is
TOC_WIDTH_RANGE, kept for a different reason — see below.Two things found while classifying
settings.svelte.tscarries a second, stale copy of the language catalogue. The group of 8 the scan flagged in that file is not one feature's leftovers; it is two unrelated things, and only the language half is interesting.SUPPORTED_LANGUAGES(:55) duplicatesgetSupportedLanguages()inutils/i18n.ts:33— same 26 entries, samecode/name/nativeNameshape — andsettings.svelte.ts:27duplicatesi18n.ts:1'sLanguageCodeunion. The live one isi18n.ts:Settings.svelte:1166-1168renders the language<select>from it.The two copies have already drifted. For
pt,i18n.tssaysPortuguese/Português;settings.svelte.tssaysPortuguese (European)/Português (Europeu). Nothing catches that, because the settings copy is only consumed for itscodecolumn —.map((entry) => entry.code)on the next line. ItsnameandnativeNameare never read by anything.So the chain is live but only one column deep:
SUPPORTED_LANGUAGES→SUPPORTED_LANGUAGE_CODES→isSupportedLanguage→ validating the persistedlanguagekey at:751. Un-exporting is correct and is all this PR does. Deleting the duplicate — or deriving the codes fromi18n.ts— is a real change with a real reason and belongs in its own PR.TOC_WIDTH_RANGEis unreferenced because its consumer re-typed the numbers. It is one of five siblingNumericSettingRangeconstants; the other four are imported and consumed bySettings.svelte.NumericSettingRange's own doc comment (settings.svelte.ts:262-266) states the contract: "Single source of truth: the settings UI rendersmin/max/stepfrom it and every write path clamps against the same object."The TOC width control is the drag handle in
MarkdownViewer.svelte, not a settings slider, and it does not import the range. It declares its own:Identical to
TOC_WIDTH_RANGE'smin/max(:209), and used for the clamp at:430, the keyboard jumps at:444/:447, andaria-valuemin/aria-valuemaxat:3468/:3469. The store's ownsetTocWidthclamps againstTOC_WIDTH_RANGEas well, so the numbers agree today by coincidence of them being typed twice.TOC_WIDTH_RANGEtherefore keeps itsexport. Its unreferenced-ness is a defect in the caller, not surplus surface, and un-exporting it would cement the duplication and make the obvious fix start by re-adding the keyword. Not fixed here — importing the range intoMarkdownViewer.sveltechanges what a wrong number would do, which is more than a visibility PR should carry.Not done
exportwith no importer. Ascripts/check in the shape ofsingleImplementationConvention.test.tscould assert it, but that is a source-text assertion with its own design questions and does not belong in the same change as the removals it would police.scripts/are untouched, as intended. Removingexportthere would delete executable tests, which is the wrong trade in this repo..sveltefiles were not scanned for their own unreferenced exports — onlysrc/lib/**/*.tswas in scope.SUPPORTED_LANGUAGES's unreadname/nativeNamecolumns are left in place. Deleting data from a declaration is a different action from narrowing its visibility, and the whole constant is a duplicate that wants resolving as one decision.npm run checkcoverssrc/andscripts/(637 files, 0 errors) and would name any broken reference;npm testis unchanged at 565 because none of these 23 were reachable from a test. The app was not launched — for a change that only removes a keyword from a declaration, there is nothing at runtime for it to observe.🤖 Generated with Claude Code