mirror of
https://github.com/callumalpass/tasknotes.git
synced 2026-07-22 12:50:26 +00:00
fix: resolve {{parentNote}} YAML parsing issues and update documentation
## Template Processing Fixes
- Add YAML-specific template processing with automatic quoting for special characters
- Fix {{parentNote}} variable causing nested arrays in YAML frontmatter
- Implement needsYamlQuoting() and escapeYamlString() for proper YAML safety
- Create processTemplateVariablesForYaml() to handle frontmatter vs body content differently
## Root Cause Resolution
The YAML parser was interpreting [[markdown links]] as nested array syntax, causing:
- `parent: [[test-13]]` → parsed as `[["test-13"]]`
- When serialized back: `parent:\n - - test-13` (double nesting)
- YAML collection warnings and malformed frontmatter
## Solution Implementation
- YAML frontmatter: {{parentNote}} → "[[Parent Note]]" (quoted string)
- Markdown body: {{parentNote}} → [[Parent Note]] (unquoted link)
- Proper string handling prevents YAML parser misinterpretation
## Documentation Updates
- Update template variable documentation in task-defaults.md and task-management.md
- Remove references to old broken behavior (newline and dash prefix)
- Add recommended best practice: use `project:\n - {{parentNote}}` for project alignment
- Provide clear examples of basic usage vs recommended project usage
- Explain benefits of list format for consistency with projects system
Fixes instant task conversion where parentNote was getting "way too nested"
and showing YAML collection warnings. Now produces clean, properly formatted
YAML with preserved markdown links.
This commit is contained in:
parent
baf8510239
commit
442318eb0a
3 changed files with 110 additions and 10 deletions
|
|
@ -46,10 +46,10 @@ Tasks can be filtered and grouped by their associated projects in all task views
|
|||
|
||||
### Template Integration
|
||||
|
||||
Projects support template variables for automated workflows. The `{{parentNote}}` variable will format the parent note link as a YAML list item (with newline and dash prefix, e.g., `\n- [[Note Name]]`) when creating tasks from project notes through instant conversion.
|
||||
Projects support template variables for automated workflows. The `{{parentNote}}` variable inserts the parent note as a properly formatted markdown link. For project organization, it's recommended to use it as a YAML list item (e.g., `project:\n - {{parentNote}}`) to align with the projects system behavior when creating tasks from project notes through instant conversion.
|
||||
|
||||
## File Management and Templates
|
||||
|
||||
TaskNotes provides a system for managing your task files. You can specify a **Default Tasks Folder** where all new tasks will be created, and you can choose from a variety of **Filename Generation** patterns, including title-based, timestamp-based, and Zettelkasten-style.
|
||||
|
||||
TaskNotes also supports **Templates** for both the YAML frontmatter and the body of your task notes. You can use templates to pre-fill common values, add boilerplate text, and create a consistent structure for your tasks. Templates can also include variables, such as `{{title}}`, `{{date}}`, and `{{parentNote}}` (which formats as a YAML list item with newline and dash prefix), which will be automatically replaced with the appropriate values when a new task is created.
|
||||
TaskNotes also supports **Templates** for both the YAML frontmatter and the body of your task notes. You can use templates to pre-fill common values, add boilerplate text, and create a consistent structure for your tasks. Templates can also include variables, such as `{{title}}`, `{{date}}`, and `{{parentNote}}` (which inserts the parent note as a properly formatted markdown link), which will be automatically replaced with the appropriate values when a new task is created.
|
||||
|
|
@ -28,17 +28,36 @@ You can set the **Default Status** and **Default Priority** for new tasks, as we
|
|||
|
||||
TaskNotes supports **Templates** for both the YAML frontmatter and the body of your task notes. You can use templates to pre-fill common values, add boilerplate text, and create a consistent structure for your tasks. Templates can also include variables, such as `{{title}}`, `{{date}}`, and `{{parentNote}}`, which will be automatically replaced with the appropriate values when a new task is created.
|
||||
|
||||
The `{{parentNote}}` variable is particularly useful for project organization. When used in a template like:
|
||||
The `{{parentNote}}` variable is particularly useful for project organization. It inserts the parent note as a properly formatted markdown link.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
When used in a template like:
|
||||
|
||||
```yaml
|
||||
projects: {{parentNote}}
|
||||
parent: {{parentNote}}
|
||||
```
|
||||
|
||||
It will resolve to:
|
||||
|
||||
```yaml
|
||||
projects:
|
||||
- [[Project Name]]
|
||||
parent: "[[Project Name]]"
|
||||
```
|
||||
|
||||
This formatting makes it easy to automatically assign tasks to the project note they were created from during instant conversion.
|
||||
### Recommended Usage for Projects
|
||||
|
||||
For better alignment with the projects system behavior, it's recommended to use `{{parentNote}}` as a list item in YAML frontmatter:
|
||||
|
||||
```yaml
|
||||
project:
|
||||
- {{parentNote}}
|
||||
```
|
||||
|
||||
This will resolve to:
|
||||
|
||||
```yaml
|
||||
project:
|
||||
- "[[Project Name]]"
|
||||
```
|
||||
|
||||
This formatting ensures consistency with how the projects system handles multiple project assignments and makes it easy to automatically assign tasks to the project note they were created from during instant conversion.
|
||||
|
|
@ -83,8 +83,8 @@ function parseTemplateSections(templateContent: string): { frontmatter: string |
|
|||
*/
|
||||
function processTemplateFrontmatter(frontmatterContent: string, taskData: TemplateData): Record<string, any> {
|
||||
try {
|
||||
// First, process template variables in the raw YAML text
|
||||
const processedYamlText = processTemplateVariables(frontmatterContent, taskData);
|
||||
// First, process template variables in the raw YAML text with YAML-safe replacements
|
||||
const processedYamlText = processTemplateVariablesForYaml(frontmatterContent, taskData);
|
||||
|
||||
// Then parse the processed YAML
|
||||
const parsedFrontmatter = parseYaml(processedYamlText);
|
||||
|
|
@ -109,6 +109,87 @@ function processTemplateBody(bodyContent: string, taskData: TemplateData): strin
|
|||
return processTemplateVariables(bodyContent, taskData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process template variables for YAML frontmatter with proper quoting
|
||||
* This version ensures that values that could break YAML parsing are properly quoted
|
||||
*/
|
||||
function processTemplateVariablesForYaml(template: string, taskData: TemplateData): string {
|
||||
let result = template;
|
||||
const now = new Date();
|
||||
|
||||
// {{title}} - Task title (quote if contains special characters)
|
||||
const title = taskData.title || '';
|
||||
const quotedTitle = needsYamlQuoting(title) ? `"${escapeYamlString(title)}"` : title;
|
||||
result = result.replace(/\{\{title\}\}/g, quotedTitle);
|
||||
|
||||
// {{priority}} - Task priority
|
||||
result = result.replace(/\{\{priority\}\}/g, taskData.priority || '');
|
||||
|
||||
// {{status}} - Task status
|
||||
result = result.replace(/\{\{status\}\}/g, taskData.status || '');
|
||||
|
||||
// {{contexts}} - Task contexts (comma-separated)
|
||||
const contexts = Array.isArray(taskData.contexts) ? taskData.contexts.join(', ') : '';
|
||||
result = result.replace(/\{\{contexts\}\}/g, contexts);
|
||||
|
||||
// {{tags}} - Task tags (comma-separated)
|
||||
const tags = Array.isArray(taskData.tags) ? taskData.tags.join(', ') : '';
|
||||
result = result.replace(/\{\{tags\}\}/g, tags);
|
||||
|
||||
// {{timeEstimate}} - Time estimate in minutes
|
||||
result = result.replace(/\{\{timeEstimate\}\}/g, taskData.timeEstimate?.toString() || '');
|
||||
|
||||
// {{dueDate}} - Due date
|
||||
result = result.replace(/\{\{dueDate\}\}/g, taskData.dueDate || '');
|
||||
|
||||
// {{scheduledDate}} - Scheduled date
|
||||
result = result.replace(/\{\{scheduledDate\}\}/g, taskData.scheduledDate || '');
|
||||
|
||||
// {{details}} - User-provided details/description
|
||||
result = result.replace(/\{\{details\}\}/g, taskData.details || '');
|
||||
|
||||
// {{parentNote}} - Parent note name/path - ALWAYS quote for YAML safety
|
||||
const parentNote = taskData.parentNote || '';
|
||||
const quotedParentNote = parentNote ? `"${escapeYamlString(parentNote)}"` : '';
|
||||
result = result.replace(/\{\{parentNote\}\}/g, quotedParentNote);
|
||||
|
||||
// {{date}} - Current date (basic format only)
|
||||
result = result.replace(/\{\{date\}\}/g, format(now, 'yyyy-MM-dd'));
|
||||
|
||||
// {{time}} - Current time (basic format only)
|
||||
result = result.replace(/\{\{time\}\}/g, format(now, 'HH:mm'));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string needs YAML quoting
|
||||
*/
|
||||
function needsYamlQuoting(str: string): boolean {
|
||||
if (!str) return false;
|
||||
|
||||
// Check for characters that have special meaning in YAML
|
||||
const yamlSpecialChars = /[\[\]{}:>|*&!%#`@,]/;
|
||||
const startsWithSpecial = /^[-?]/;
|
||||
const looksLikeNumber = /^\d+\.?\d*$/;
|
||||
const looksLikeBoolean = /^(true|false|yes|no|on|off)$/i;
|
||||
|
||||
return yamlSpecialChars.test(str) ||
|
||||
startsWithSpecial.test(str) ||
|
||||
looksLikeNumber.test(str) ||
|
||||
looksLikeBoolean.test(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a string for safe use in YAML quotes
|
||||
*/
|
||||
function escapeYamlString(str: string): string {
|
||||
if (!str) return '';
|
||||
|
||||
// Escape backslashes and double quotes
|
||||
return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process task template variables like {{title}}, {{priority}}, {{status}}, etc.
|
||||
* This is the core variable replacement function used by both frontmatter and body processing
|
||||
|
|
@ -147,7 +228,7 @@ function processTemplateVariables(template: string, taskData: TemplateData): str
|
|||
result = result.replace(/\{\{details\}\}/g, taskData.details || '');
|
||||
|
||||
// {{parentNote}} - Parent note name/path where task was created
|
||||
result = result.replace(/\{\{parentNote\}\}/g, taskData.parentNote ? `\n- ${taskData.parentNote}` : '');
|
||||
result = result.replace(/\{\{parentNote\}\}/g, taskData.parentNote || '');
|
||||
|
||||
// {{date}} - Current date (basic format only)
|
||||
result = result.replace(/\{\{date\}\}/g, format(now, 'yyyy-MM-dd'));
|
||||
|
|
|
|||
Loading…
Reference in a new issue