-
-
Notifications
You must be signed in to change notification settings - Fork 195
fix: the file-name preview tells the truth on every surface, and the run stops before the damage #1618
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
fix: the file-name preview tells the truth on every surface, and the run stops before the damage #1618
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
0edcdc1
fix(preview): resolve {{MVALUE}}, and stop discarding the collected a…
chhoumann 4ab6530
fix(preview): give {{VDATE:}} the run's default format, and its answe…
chhoumann 0cd531c
fix(preview): say so when a file-name format uses {{title}}
chhoumann 19332b4
fix(preview): stop labelling a resolved name "Unresolved:"
chhoumann f9b403e
fix(preview): give the one-page form its diagnostics and its target f…
chhoumann 731f8c3
fix: refuse an impossible file name before running the template body
chhoumann 9963e61
fix(preview): fold in the adversarial review of this branch
chhoumann 957260d
test(preview): anchor the seeded VDATE instant to local time
chhoumann d190bed
fix(preview): treat an inline-script folder as unknown, and pin two g…
chhoumann da6e01c
test(preview): pin that a slow preview pass is stale, never mixed
chhoumann File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| import { describe, expect, it, vi } from "vitest"; | ||
| import { ChoiceAbortError } from "../errors/ChoiceAbortError"; | ||
|
|
||
| /** | ||
| * Issue #1591. `createFileWithTemplate` reads the template, formats the ENTIRE | ||
| * body - real `{{VALUE}}` prompts, macros, and inline `js quickadd` fences with | ||
| * their side effects - and only then hands the path to `createFileWithInput`, | ||
| * which creates the target FOLDER before `vault.create` refuses the name. | ||
| * | ||
| * Measured on Obsidian 1.13.0 (isolated e2e vault) before the fix: a Template | ||
| * choice named `Bad: {{VALUE:title}}` reported "no file was created" AND left | ||
| * `Repro1591Folder` behind AND had run the template's inline script once. | ||
| * | ||
| * The guard is the first statement of `createFileWithTemplate`, so this asserts | ||
| * on the observable consequence: nothing downstream of it is reached. | ||
| */ | ||
|
|
||
| vi.mock("obsidian", async () => { | ||
| const actual = await import("../../tests/obsidian-stub"); | ||
| return actual; | ||
| }); | ||
| vi.mock("../formatters/completeFormatter", () => ({ | ||
| CompleteFormatter: class { | ||
| setTitle() {} | ||
| setTargetFolderPath() {} | ||
| setPromptRunContext() {} | ||
| setTemplateInclusionState() {} | ||
| }, | ||
| })); | ||
| vi.mock("../utilityObsidian", () => ({ | ||
| getTemplateFile: vi.fn(), | ||
| getTemplater: vi.fn(() => null), | ||
| overwriteTemplaterOnce: vi.fn(), | ||
| templaterParseTemplate: vi.fn(), | ||
| })); | ||
| vi.mock("../logger/logManager", () => ({ | ||
| log: { logWarning: vi.fn(), logError: vi.fn(), logMessage: vi.fn() }, | ||
| })); | ||
|
|
||
| const { TemplateEngine } = await import("./TemplateEngine"); | ||
|
|
||
| class ProbeEngine extends (TemplateEngine as never as new ( | ||
| ...args: never[] | ||
| ) => Record<string, unknown>) { | ||
| public readTemplate = vi.fn(); | ||
| public created = vi.fn(); | ||
|
|
||
| constructor() { | ||
| super( | ||
| { vault: {}, workspace: {} } as never, | ||
| { settings: {} } as never, | ||
| ); | ||
| } | ||
|
|
||
| run() { | ||
| return Promise.resolve(); | ||
| } | ||
|
|
||
| // Everything the guard must run BEFORE. | ||
| protected getTemplateContent(path: string) { | ||
| this.readTemplate(path); | ||
| return Promise.resolve("body"); | ||
| } | ||
| protected createFileWithInput(path: string) { | ||
| this.created(path); | ||
| return Promise.resolve({ path }); | ||
| } | ||
| } | ||
|
|
||
| function makeEngine() { | ||
| return new ProbeEngine() as unknown as ProbeEngine & { | ||
| createFileWithTemplate: ( | ||
| filePath: string, | ||
| templatePath: string, | ||
| ) => Promise<unknown>; | ||
| }; | ||
| } | ||
|
|
||
| describe("createFileWithTemplate refuses an impossible name first (#1591)", () => { | ||
| it("aborts without reading the template or creating anything", async () => { | ||
| const engine = makeEngine(); | ||
|
|
||
| await expect( | ||
| engine.createFileWithTemplate("Notes/Bad: My Note.md", "T.md"), | ||
| ).rejects.toBeInstanceOf(ChoiceAbortError); | ||
|
|
||
| expect(engine.readTemplate).not.toHaveBeenCalled(); | ||
| expect(engine.created).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it("aborts for a colon in a FOLDER segment, before the folder is created", async () => { | ||
| const engine = makeEngine(); | ||
|
|
||
| await expect( | ||
| engine.createFileWithTemplate("Meetings: 2026/Note.md", "T.md"), | ||
| ).rejects.toBeInstanceOf(ChoiceAbortError); | ||
|
|
||
| expect(engine.readTemplate).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it("leaves a legal path alone", async () => { | ||
| // Getting as far as reading the template is what proves the guard let it | ||
| // through; the rest of the create path needs the real formatter and is | ||
| // covered by TemplateChoiceEngine's own suites. | ||
| const engine = makeEngine(); | ||
|
|
||
| await engine.createFileWithTemplate("Notes/My Note.md", "T.md"); | ||
|
|
||
| expect(engine.readTemplate).toHaveBeenCalledWith("T.md"); | ||
| }); | ||
| }); |
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
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.