mirror of
https://github.com/kdnk/obsidian-automatic-linker.git
synced 2026-07-22 05:37:46 +00:00
fix(formatting): restore selection-only link replacement
Why: - The selection command regressed by inheriting document-level URL formatting from the shared body formatter. - That changed user-visible output for selected text containing GitHub, Jira, or Linear URLs. What: - Added a selection-only formatter that projects link replacement settings and calls `replaceLinks(...)` directly. - Switched `mofifyLinksSelection()` to the new helper so document formatting stays unchanged. - Added regression coverage for selection-only behavior and documented the fix in the task report.
This commit is contained in:
parent
73014eb012
commit
6585b7393a
5 changed files with 156 additions and 2 deletions
|
|
@ -83,3 +83,49 @@ Results:
|
|||
## Concerns
|
||||
|
||||
None.
|
||||
|
||||
## Fix: Selection Formatting Regression
|
||||
|
||||
Selection formatting was accidentally routed through `formatMarkdownBody(...)`, which let URL-formatting behavior leak into the selection command.
|
||||
|
||||
### RED
|
||||
|
||||
Command:
|
||||
|
||||
```bash
|
||||
npx vitest run src/__tests__/main-link-generator.test.ts
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
- Failed as expected
|
||||
- Failure showed `mofifyLinksSelection()` was formatting a GitHub URL instead of leaving it unchanged:
|
||||
`[[notes/TypeScript|TypeScript]] [[github/openai/openai/issues/1]] [🔗](https://github.com/openai/openai/issues/1)`
|
||||
|
||||
### GREEN
|
||||
|
||||
Changes:
|
||||
|
||||
- Added `formatMarkdownSelection(...)` in `src/formatting-run.ts`
|
||||
- Updated `mofifyLinksSelection()` in `src/main.ts` to call the selection-only helper
|
||||
- Added a unit guard in `src/__tests__/formatting-run.test.ts`
|
||||
|
||||
### Verification
|
||||
|
||||
Commands:
|
||||
|
||||
```bash
|
||||
npx vitest run src/__tests__/formatting-run.test.ts src/__tests__/main-link-generator.test.ts
|
||||
npm run tsc
|
||||
npm run lint
|
||||
```
|
||||
|
||||
Results:
|
||||
|
||||
- `npx vitest run src/__tests__/formatting-run.test.ts src/__tests__/main-link-generator.test.ts`: passed `2` files, `7` tests
|
||||
- `npm run tsc`: exit `0`
|
||||
- `npm run lint`: exit `0`
|
||||
|
||||
### Concerns
|
||||
|
||||
- Selection formatting now has its own helper; any future selection-specific behavior should be added there, not to `formatMarkdownBody(...)`.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest"
|
|||
import {
|
||||
formatMarkdownBody,
|
||||
formatMarkdownDocument,
|
||||
formatMarkdownSelection,
|
||||
toReplaceLinksSettings,
|
||||
} from "../formatting-run"
|
||||
import { buildCandidateTrieForTest } from "../replace-links/__tests__/test-helpers"
|
||||
|
|
@ -111,3 +112,34 @@ describe("formatMarkdownBody", () => {
|
|||
expect(result).toBe("[[notes/TypeScript|TypeScript]]")
|
||||
})
|
||||
})
|
||||
|
||||
describe("formatMarkdownSelection", () => {
|
||||
it("keeps selection formatting to link replacement only", () => {
|
||||
const { candidateMap, trie } = buildCandidateTrieForTest({
|
||||
files: [{ path: "notes/TypeScript" }],
|
||||
settings: {
|
||||
scoped: false,
|
||||
baseDir: undefined,
|
||||
ignoreCase: true,
|
||||
},
|
||||
})
|
||||
|
||||
const result = formatMarkdownSelection({
|
||||
body: "TypeScript https://github.com/openai/openai/issues/1",
|
||||
filePath: "current-file.md",
|
||||
settings: {
|
||||
...DEFAULT_SETTINGS,
|
||||
formatGitHubURLs: true,
|
||||
formatJiraURLs: true,
|
||||
formatLinearURLs: true,
|
||||
replaceUrlWithTitle: true,
|
||||
ignoreCase: true,
|
||||
},
|
||||
candidateIndex: { candidateMap, trie },
|
||||
})
|
||||
|
||||
expect(result).toBe(
|
||||
"[[notes/TypeScript|TypeScript]] https://github.com/openai/openai/issues/1",
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -76,4 +76,56 @@ describe("AutomaticLinkerPlugin link generator", () => {
|
|||
|
||||
expect(result).toBe("| [[notes/foo\\|bar]] | x |\n| --- | --- |\n")
|
||||
})
|
||||
|
||||
it("keeps selection formatting to link replacement only", async () => {
|
||||
const { default: AutomaticLinkerPlugin } = await import("../main")
|
||||
const settings = {
|
||||
scoped: false,
|
||||
baseDir: undefined,
|
||||
ignoreCase: true,
|
||||
}
|
||||
const { candidateMap, trie } = buildCandidateTrieForTest({
|
||||
files: [{ path: "notes/TypeScript" }],
|
||||
settings,
|
||||
})
|
||||
const replaceSelection = vi.fn()
|
||||
const app = {
|
||||
workspace: {
|
||||
getActiveFile: vi.fn(() => ({ path: "current-file.md" })),
|
||||
activeEditor: {
|
||||
editor: {
|
||||
getSelection: vi.fn(() => "TypeScript https://github.com/openai/openai/issues/1"),
|
||||
replaceSelection,
|
||||
},
|
||||
},
|
||||
},
|
||||
vault: {
|
||||
getConfig: vi.fn(() => "pages"),
|
||||
getAbstractFileByPath: vi.fn((path: string) => {
|
||||
if (path === "notes/TypeScript.md") return { path: "notes/TypeScript.md" }
|
||||
return null
|
||||
}),
|
||||
},
|
||||
fileManager: {
|
||||
generateMarkdownLink: vi.fn(() => "[[notes/TypeScript|TypeScript]]"),
|
||||
},
|
||||
}
|
||||
const plugin = new AutomaticLinkerPlugin(app as never, {} as never)
|
||||
plugin.settings = {
|
||||
...DEFAULT_SETTINGS,
|
||||
formatGitHubURLs: true,
|
||||
formatJiraURLs: true,
|
||||
formatLinearURLs: true,
|
||||
replaceUrlWithTitle: true,
|
||||
respectNewFileFolderPath: true,
|
||||
}
|
||||
;(plugin as unknown as { trie: typeof trie }).trie = trie
|
||||
;(plugin as unknown as { candidateMap: typeof candidateMap }).candidateMap = candidateMap
|
||||
|
||||
await plugin.mofifyLinksSelection()
|
||||
|
||||
expect(replaceSelection).toHaveBeenCalledWith(
|
||||
"[[notes/TypeScript|TypeScript]] https://github.com/openai/openai/issues/1",
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -84,6 +84,30 @@ export const formatMarkdownBody = ({
|
|||
return updatedBody
|
||||
}
|
||||
|
||||
export const formatMarkdownSelection = ({
|
||||
body,
|
||||
filePath,
|
||||
settings,
|
||||
baseDir,
|
||||
candidateIndex,
|
||||
linkGenerator,
|
||||
}: Omit<FormattingRunOptions, "content" | "frontmatter" | "urlTitleMap"> & { body: string }): string => {
|
||||
if (!candidateIndex) {
|
||||
return body
|
||||
}
|
||||
|
||||
return replaceLinks({
|
||||
body,
|
||||
linkResolverContext: {
|
||||
filePath: filePath.replace(/\.md$/, ""),
|
||||
trie: candidateIndex.trie,
|
||||
candidateMap: candidateIndex.candidateMap,
|
||||
},
|
||||
settings: toReplaceLinksSettings(settings, baseDir),
|
||||
linkGenerator,
|
||||
})
|
||||
}
|
||||
|
||||
const inferContentStart = (content: string): number => {
|
||||
const frontmatter = content.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/)
|
||||
return frontmatter?.[0].length ?? 0
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import {
|
|||
} from "obsidian"
|
||||
import { excludeLinks } from "./exclude-links"
|
||||
import {
|
||||
formatMarkdownBody,
|
||||
formatMarkdownDocument,
|
||||
formatMarkdownSelection,
|
||||
toReplaceLinksSettings,
|
||||
} from "./formatting-run"
|
||||
import {
|
||||
|
|
@ -233,7 +233,7 @@ export default class AutomaticLinkerPlugin extends Plugin {
|
|||
|
||||
const linkGenerator = this.createLinkGenerator(activeFile.path)
|
||||
const baseDir = this.settings.respectNewFileFolderPath ? this.app.vault.getConfig("newFileFolderPath") : undefined
|
||||
const updatedText = formatMarkdownBody({
|
||||
const updatedText = formatMarkdownSelection({
|
||||
body: selectedText,
|
||||
filePath: activeFile.path,
|
||||
settings: this.settings,
|
||||
|
|
|
|||
Loading…
Reference in a new issue