Skip to content

Commit cb39ed4

Browse files
committed
fix: disallow capture targets with .base extension
1 parent 964d672 commit cb39ed4

File tree

3 files changed

+41
-15
lines changed

3 files changed

+41
-15
lines changed

docs/docs/Choices/CaptureChoice.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ You can choose to either enable _Capture to active file_, or you can enter a fil
1818

1919
QuickAdd treats file names as basename-first by default:
2020
- If you do **not** provide an extension, QuickAdd creates/targets a Markdown file (`.md`).
21-
- If you provide an explicit extension (for example `Project.base`), QuickAdd keeps that extension.
21+
- If you provide an explicit supported extension (for example `.md` or `.canvas`), QuickAdd keeps that extension.
22+
- Capture to `.base` files is not supported. Use a Template choice for `.base` workflows.
2223

2324
This field also supports the [format syntax](/FormatSyntax.md), which allows you to use dynamic file names.
2425
I have one for my daily journal with the name `bins/daily/{{DATE:gggg-MM-DD - ddd MMM D}}.md`.

src/engine/CaptureChoiceEngine.selection.test.ts

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { CaptureChoiceEngine } from "./CaptureChoiceEngine";
44
import type ICaptureChoice from "../types/choices/ICaptureChoice";
55
import type { IChoiceExecutor } from "../IChoiceExecutor";
66
import { isFolder, openFile } from "../utilityObsidian";
7+
import { QA_INTERNAL_CAPTURE_TARGET_FILE_PATH } from "../constants";
8+
import { ChoiceAbortError } from "../errors/ChoiceAbortError";
79

810
const { setUseSelectionAsCaptureValueMock, setTitleMock } = vi.hoisted(() => ({
911
setUseSelectionAsCaptureValueMock: vi.fn(),
@@ -270,7 +272,7 @@ describe("CaptureChoiceEngine capture target resolution", () => {
270272
expect(result).toEqual({ kind: "file", path: "journals" });
271273
});
272274

273-
it("preserves explicit .base capture target paths", async () => {
275+
it("rejects explicit .base capture target paths", () => {
274276
const app = createApp();
275277
const engine = new CaptureChoiceEngine(
276278
app,
@@ -279,9 +281,28 @@ describe("CaptureChoiceEngine capture target resolution", () => {
279281
createExecutor(),
280282
);
281283

282-
const result = await (engine as any).getFormattedPathToCaptureTo(false);
284+
expect(() =>
285+
(engine as any).resolveCaptureTarget("Boards/Kanban.base"),
286+
).toThrow(ChoiceAbortError);
287+
});
283288

284-
expect(result).toBe("Boards/Kanban.base");
289+
it("rejects preselected .base capture target paths", async () => {
290+
const app = createApp();
291+
const executor = createExecutor();
292+
executor.variables.set(
293+
QA_INTERNAL_CAPTURE_TARGET_FILE_PATH,
294+
"Boards/Kanban.base",
295+
);
296+
const engine = new CaptureChoiceEngine(
297+
app,
298+
{ settings: { useSelectionAsCaptureValue: false } } as any,
299+
createChoice(),
300+
executor,
301+
);
302+
303+
await expect(
304+
(engine as any).getFormattedPathToCaptureTo(false),
305+
).rejects.toBeInstanceOf(ChoiceAbortError);
285306
});
286307

287308
it("preserves explicit .canvas capture target paths", async () => {
@@ -298,7 +319,7 @@ describe("CaptureChoiceEngine capture target resolution", () => {
298319
expect(result).toBe("Boards/Map.canvas");
299320
});
300321

301-
it("uses extensionless title for created .base/.canvas capture files", async () => {
322+
it("uses extensionless title for created .canvas capture files", async () => {
302323
const app = createApp() as any;
303324
app.vault.read = vi.fn(async () => "");
304325

@@ -321,16 +342,11 @@ describe("CaptureChoiceEngine capture target resolution", () => {
321342
extension: path.endsWith(".base") ? "base" : "canvas",
322343
}));
323344

324-
await (engine as any).onCreateFileIfItDoesntExist(
325-
"Boards/Kanban.base",
326-
"capture",
327-
);
328345
await (engine as any).onCreateFileIfItDoesntExist(
329346
"Boards/Map.canvas",
330347
"capture",
331348
);
332349

333-
expect(setTitleMock).toHaveBeenCalledWith("Kanban");
334350
expect(setTitleMock).toHaveBeenCalledWith("Map");
335351
});
336352
});

src/engine/CaptureChoiceEngine.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ export class CaptureChoiceEngine extends QuickAddChoiceEngine {
251251
typeof preselected === "string" &&
252252
preselected.length > 0
253253
) {
254-
return preselected;
254+
return this.normalizeCaptureFilePath(preselected);
255255
}
256256

257257
if (shouldCaptureToActiveFile) {
@@ -308,6 +308,12 @@ export class CaptureChoiceEngine extends QuickAddChoiceEngine {
308308
};
309309
}
310310

311+
if (BASE_FILE_EXTENSION_REGEX.test(normalizedCaptureTo)) {
312+
throw new ChoiceAbortError(
313+
`Capture to '.base' files is not supported (${normalizedCaptureTo}). Use a Template choice instead.`,
314+
);
315+
}
316+
311317
const endsWithSlash = normalizedCaptureTo.endsWith("/");
312318
const folderPath = normalizedCaptureTo.replace(/\/+$/, "");
313319

@@ -317,8 +323,7 @@ export class CaptureChoiceEngine extends QuickAddChoiceEngine {
317323

318324
if (
319325
MARKDOWN_FILE_EXTENSION_REGEX.test(normalizedCaptureTo) ||
320-
CANVAS_FILE_EXTENSION_REGEX.test(normalizedCaptureTo) ||
321-
BASE_FILE_EXTENSION_REGEX.test(normalizedCaptureTo)
326+
CANVAS_FILE_EXTENSION_REGEX.test(normalizedCaptureTo)
322327
) {
323328
return { kind: "file", path: normalizedCaptureTo };
324329
}
@@ -562,10 +567,14 @@ export class CaptureChoiceEngine extends QuickAddChoiceEngine {
562567

563568
private normalizeCaptureFilePath(path: string): string {
564569
const normalizedPath = this.stripLeadingSlash(path);
570+
if (BASE_FILE_EXTENSION_REGEX.test(normalizedPath)) {
571+
throw new ChoiceAbortError(
572+
`Capture to '.base' files is not supported (${normalizedPath}). Use a Template choice instead.`,
573+
);
574+
}
565575
if (
566576
MARKDOWN_FILE_EXTENSION_REGEX.test(normalizedPath) ||
567-
CANVAS_FILE_EXTENSION_REGEX.test(normalizedPath) ||
568-
BASE_FILE_EXTENSION_REGEX.test(normalizedPath)
577+
CANVAS_FILE_EXTENSION_REGEX.test(normalizedPath)
569578
) {
570579
return normalizedPath;
571580
}

0 commit comments

Comments
 (0)