fix: align output path pattern resolution with documented behavior#2473
fix: align output path pattern resolution with documented behavior#2473Myriad-Dreamin wants to merge 4 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes Tinymist export output-path pattern resolution to match documented behavior, addressing regressions around multi-dot filenames and workspace-root exports.
Changes:
- Adjust
PathPatternsubstitution so emptytinymist.outputPathresolves like the documented default and$dirdoesn’t accidentally become filesystem-rooted for workspace-root files. - Update export path preparation to resolve relative output paths against the workspace root and preserve multi-dot stems when applying artifact extensions.
- Add regression tests and an OpenSpec requirements spec capturing the expected semantics.
Reviewed changes
Copilot reviewed 4 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| openspec/specs/output-path-patterns/spec.md | Adds a spec for output-path pattern semantics and regression scenarios. |
| openspec/changes/archive/2026-04-04-fix-output-path-pattern-regressions/tasks.md | Marks the spec-driven change tasks as completed. |
| openspec/changes/archive/2026-04-04-fix-output-path-pattern-regressions/specs/output-path-patterns/spec.md | Archives the added output-path pattern requirements for the change record. |
| openspec/changes/archive/2026-04-04-fix-output-path-pattern-regressions/README.md | Summarizes the archived change for issue #2400. |
| openspec/changes/archive/2026-04-04-fix-output-path-pattern-regressions/proposal.md | Provides rationale and intended behavior changes for the regression fix. |
| openspec/changes/archive/2026-04-04-fix-output-path-pattern-regressions/.openspec.yaml | Adds OpenSpec metadata for the archived change. |
| crates/tinymist/src/task/export.rs | Changes how export output paths are rooted and how extensions are applied; adds export-path regression tests. |
| crates/tinymist-task/src/primitives.rs | Fixes $dir substitution and empty-pattern default resolution; adds substitution regression tests. |
| let write_to = Self::append_extension(write_to, task.extension()); | ||
|
|
||
| Ok(Some(write_to)) | ||
| } | ||
|
|
||
| fn append_extension(path: PathBuf, extension: &str) -> PathBuf { | ||
| let Some(file_name) = path.file_name() else { | ||
| return path.with_file_name(format!("main.{extension}")); | ||
| }; | ||
|
|
||
| let mut file_name = file_name.to_os_string(); | ||
| file_name.push("."); | ||
| file_name.push(extension); | ||
| path.with_file_name(file_name) | ||
| } |
There was a problem hiding this comment.
append_extension always appends .{extension} to the existing filename, which can produce duplicated extensions (e.g. an outputPath pattern like $root/$dir/$name.pdf or a page_number_template that already includes .png will become ...pdf.pdf / ...png.png). This is a behavior change from the previous with_extension semantics and is likely to break existing configurations. Consider detecting an existing matching extension and avoiding re-appending (and/or normalizing the filename before applying the artifact extension).
| ## ADDED Requirements | ||
|
|
There was a problem hiding this comment.
This spec file under openspec/specs/ uses the archive-style heading ## ADDED Requirements and lacks the standard # <name> Specification title + ## Purpose section used by other specs in this directory (e.g. openspec/specs/math-module-field-completion/spec.md). To keep the specs consistent and discoverable, please reformat this file to follow the established spec template (title, purpose, then requirements).
| ## ADDED Requirements | |
| # Output Path Patterns Specification | |
| ## Purpose | |
| Define how Tinymist resolves output path pattern variables in `tinymist.outputPath`, with particular focus on preserving the full `$name` source stem, handling empty `$dir` values as workspace-relative paths, and ensuring that explicit `$dir/$name` output patterns match the default export location. | |
| ## Requirements |
Closes #2400.
Summary
$dir/$nameoutputs for workspace-root files inside the workspace instead of resolving to/...tinymist.outputPathresolve like the documented default$root/$dir/$nameTesting
cargo fmt --check --allcargo test -p tinymist-task --features no-content-hint test_substitute_path -- --nocapturecargo test -p tinymist-task --features no-content-hint primitives::tests::test_substitute_default_path_matches_documented_behavior -- --exact --nocapturecargo test -p tinymist --no-default-features --features export,system,no-content-hint task::export::tests::test_prepare_output_path_preserves_multi_dot_pdf_names -- --exact --nocapturecargo test -p tinymist --no-default-features --features export,system,no-content-hint task::export::tests::test_prepare_output_path_explicit_dir_name_matches_default -- --exact --nocapture