Skip to content

feat(format): support Obsidian property types in format syntax (#757)#1367

Merged
chhoumann merged 10 commits into
masterfrom
chhoumann/757-property-types-feasibility
Jun 16, 2026
Merged

feat(format): support Obsidian property types in format syntax (#757)#1367
chhoumann merged 10 commits into
masterfrom
chhoumann/757-property-types-feasibility

Conversation

@chhoumann

@chhoumann chhoumann commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Closes #757.

Full format-syntax support for Obsidian's property types. Everything output stays raw-inline (no processFrontMatter, so YAML comments are preserved) except multi-select, which reuses the existing always-on array→List pipeline.

What's new

Token Behaviour
{{VALUE:x|type:number}} Numeric input prompt; writes x: 42Number
{{VALUE:x|type:checkbox}} (alias |type:boolean) Forced true/false picker (the |label: is its title); writes x: trueCheckbox
{{VALUE:x|type:text}} Quotes the value (id: "0042") so a number/bool/YAML-indicator-looking string stays Text
{{VALUE:a,b,c|multi}} Multi-select picker → a real YAML List (no setting required). |multi:linklist wraps picks as [[name]]; |multi|custom adds off-list values
{{VDATE:when,fmt|time}} (alias |datetime) Adds a time control to the date picker; a day-click merges the picked day with the set time

Plain {{VALUE}} already round-trips numbers/booleans/dates to the correct type — these options add the right input widget + validation, and |type:text closes the inverse footgun (a text value Obsidian would otherwise retype).

Also fixes a pre-existing red tsc/pnpm build at HEAD (a {{linksection}} test stub didn't implement the abstract suggestForFile added by the {{FILE:}} token).

How it was verified

Every feature was driven end-to-end in an isolated Obsidian vault (pnpm run obsidian:e2e), reading back the created note's frontmatter and parsed types — e.g. n: 42→number, done: true→boolean, id: "0042"→string, tags: [work, urgent] (flag OFF), when: 2026-06-15T14:30. The "what Obsidian coerces" rules were pinned empirically against Obsidian's own parser.

pnpm run build-with-lint green; 2328 unit tests pass (Vitest).

Review

Hardened across two adversarial review rounds. Notably: an earlier auto-quoting path was removed after verifying metadataTypeManager.getTypeInfo().expected.type returns "text" even for undeclared keys (it would have quoted every 42/true under the beta flag); |type:text now quotes unconditionally at a sole-value front-matter position (covering #todo/[a]/trailing-comment cases), and only via the explicit token.

Known limitations (documented)

  • An empty |type:text input writes an empty/null value (consistent with every other token), not "".
  • The opt-in one-page input form can't round-trip a comma inside a single |multi option; the default one-prompt-at-a-time picker handles it correctly.

Docs

docs/docs/FormatSyntax.md + docs/docs/TemplatePropertyTypes.md (Next/unreleased only).

Summary by CodeRabbit

Release Notes

  • New Features

    • Multi-select option lists via {{VALUE:<options>|multi}}, including YAML list output and optional wikilink emission using |multi:linklist.
    • Date/time picking for {{VDATE}} using |time/|datetime (with updated datetime default formatting).
    • New input type overrides: |type:number, |type:checkbox/|type:boolean, and |type:text, plus support for number input prompts and checkbox-style prompts.
  • Documentation

    • Updated guidance for |multi and format/token input-type selection.
  • Bug Fixes

    • Warning added for capture cases where |multi may render as a comma-separated string instead of a YAML list.
  • Tests

    • Expanded coverage for multi-select, value/type parsing, and date/time picker behavior.

The {{FILE:}} token (#1357) added an abstract suggestForFile to Formatter,
but the {{linksection}} test stub (#387) never implemented it, leaving
'tsc -noEmit' (and thus 'pnpm run build') red at HEAD. Add the trivial stub
to match the other test formatters.
Closes part of #757. Extends the VALUE token's |type: option (previously
multiline-only) with:
- |type:number  -> a validated numeric input (NumberInputPrompt, <input
  type=number>), so the written 'x: 42' round-trips as an Obsidian Number.
- |type:checkbox (alias |type:boolean) -> a forced true/false suggester (the
  |label becomes its title), so 'x: true' round-trips as a Checkbox.
- |type:text -> a normal prompt that marks the value for type-aware YAML
  quoting (the quoting itself lands in a follow-up commit).

Output stays raw-inline (no processFrontMatter / comment-strip); the scalar
already inferred correctly, this adds the input affordance + validation. The
one-page input form renders checkbox as a true/false dropdown for parity.
e2e-verified: number input renders type=number; checkbox shows true/false;
seeded runs write 'n: 42' (number) and 'done: true' (boolean).
…g type

Closes part of #757 (the inverse coercion footgun). A {{VALUE}} written raw
into frontmatter is parsed by Obsidian's YAML, which coerces strings like
"0042" -> 42 and "true" -> boolean, silently changing a text property's
type. QuickAdd now emits a double-quoted YAML scalar when:
  - the value is one Obsidian actually coerces (wouldYamlMisCoerce, pinned
    EMPIRICALLY against Obsidian's parser — yes/no/on/off, underscores and
    dates are NOT coerced, so they are deliberately left unquoted), AND
  - the token is the sole value at a frontmatter key:value or list-item
    position and not already author-quoted, AND
  - the author used |type:text, OR (under enableTemplatePropertyTypes, in a
    collection scope) the property is EXPLICITLY declared a Text type.

Quoting is inline (no processFrontMatter), so YAML comments are preserved and
number/checkbox/date round-tripping is unchanged. New pure yamlScalarQuoting
helpers; isListItemPosition added to yamlContext. e2e-verified: id: "0042"
(string) with comment kept; hello/dates stay unquoted; flag-off unchanged.
Closes part of #757. The VDATE prompt already opened a calendar; this adds an
opt-in time control:
- New |time flag (aliases |datetime and |type:datetime) parsed in vdateSyntax;
  the keyed |type: form is consumed so it never leaks into the natural-language
  default. Tokens without it stay byte-identical (withTime:false).
- datePicker renders an <input type=time> when withTime; a day-click MERGES the
  selected day with the current time instead of overwriting to midnight, and
  editing the time after picking a day updates the value. The emitted ISO is an
  offset-less local 'YYYY-MM-DDTHH:mm:00' so the hour round-trips in every
  timezone (never toISOString/Z).
- |time with no explicit format defaults to 'YYYY-MM-DD HH:mm'.
- VDateInputPrompt mounts the picker from the constructor body (not during the
  super() display() pass) so this.withTime is set first. One-page input form
  threads withTime to its picker for parity.

e2e-verified: time control renders; picking day 15 + 14:30 writes
'when: 2026-06-15T14:30'; the time survives a day-click.
Closes the headline #757 ask (and #621). A new |multi flag turns an option-list
VALUE token into a multi-select picker that writes a real YAML list:
- New MultiSuggester modal (toggle list + optional custom-add + Skip) returns
  string[]. |multi|custom adds off-list values; |multi:linklist wraps each pick
  as [[name]].
- The result is stored as an ARRAY, so it flows through the always-on container
  collector -> processFrontMatter -> a proper YAML list, INDEPENDENT of the
  enableTemplatePropertyTypes beta flag.
- Guards from adversarial review: |case is dropped on |multi (warn) and the
  non-collected fallback joins arrays with commas, so |multi|case and body-
  position |multi can't throw or emit broken YAML; the capture engine warns when
  |multi can't become a list (non-new-file/append/existing-note captures).
- One-page input parity: |multi sets suggesterConfig.multiSelect independently
  of |custom, and the joined modal value is split back into an array (with
  linklist wrapping) before it reaches the formatter.

e2e-verified with the flag OFF: |multi -> [work, urgent]; |multi:linklist ->
["[[Alice]]","[[Carol]]"]; |multi|custom -> [work, zeta]; body position ->
'a,c' (comma string, no broken YAML).
Document the new format-syntax options in docs/docs (Next/unreleased only, not
the versioned snapshot):
- {{VALUE:x|type:number|checkbox|text}} property-type inputs + the note that
  plain numbers/booleans/dates already round-trip and |type:text closes the
  text-looks-like-a-number footgun.
- {{VALUE:a,b,c|multi}} multi-select List picker (+ |multi:linklist, |multi
  |custom, capture caveat).
- {{VDATE:when,fmt|time}} date & time picker.
Cross-links added from Template Property Types.
High-severity (verified in-vault):
- Drop the AUTO |type:text path. metadataTypeManager.getTypeInfo reports
  expected.type 'text' even for undeclared keys (verified), so auto-quoting
  under the beta flag would have quoted EVERY coercion-prone scalar — e.g.
  an undeclared number property 'rating: 42' -> '"42"'. Now only explicit
  |type:text quotes; the flag no longer affects quoting.
- |type:text now ALWAYS quotes at a sole-value front-matter position instead
  of only for number/bool/null. A coercion-only predicate missed YAML
  indicator values (#todo -> null, [a] -> array, 'a: b' -> broken YAML);
  quoting unconditionally there is bulletproof. Replaced wouldYamlMisCoerce
  with a pure shouldQuoteTextScalar (position-only); removed the now-unused
  getTypeInfo/expectedType plumbing from the collector.

Medium:
- Honor |type:text/number on the anonymous {{VALUE|...}} form (was parsed but
  ignored): propagate inputTypeOverride into the value prompt context and quote
  |type:text in its replacement.
- One-page input parity: render |type:number as a numeric field, and map
  one-page multi-select DISPLAY labels back to option values (so |text:
  mappings round-trip) before splitting into the array.

Low:
- Capture |multi warning no longer false-fires on |type:multiline (precise
  regex), and named-conflict detection now includes multiSelect/multiEmit.

All e2e re-verified: flag ON + undeclared number/checkbox stay number/boolean;
|type:text quotes 0042/#todo/[a]; anonymous {{VALUE|type:text}} quotes.
- shouldQuoteTextScalar now treats a token followed only by a trailing YAML
  comment (` #…`) as the sole value, so `id: {{VALUE:id|type:text}} # keep`
  with input `#todo` writes `id: "#todo" # keep` (string, comment preserved)
  instead of `id: #todo` (which Obsidian read as null). Shared yamlContext
  position helper, so the collector benefits too.
- quoteYamlDouble escapes newlines/tabs/CR so a script-seeded multi-line value
  stays valid YAML.
- Tighten the capture |multi warning regex to the exact flag (`|multi`
  terminated by :/|/}/end), avoiding false positives on |multi1 / |multi-select.

Documented one-page-form limitation: a comma inside a single |multi option
can't round-trip there (the default picker handles it). Empty |type:text input
intentionally stays null (no value), consistent with all other tokens.
All tests/lint/build green; trailing-comment fix e2e-verified.
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 74bc55aa-1594-4e69-adf7-1e952a485fd6

📥 Commits

Reviewing files that changed from the base of the PR and between abe9196 and 43994d5.

📒 Files selected for processing (6)
  • src/formatters/completeFormatter.ts
  • src/formatters/formatter.ts
  • src/gui/date-picker/datePicker.test.ts
  • src/gui/date-picker/datePicker.ts
  • src/preflight/RequirementCollector.ts
  • src/preflight/runOnePagePreflight.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/preflight/runOnePagePreflight.ts
  • src/formatters/completeFormatter.ts
  • src/gui/date-picker/datePicker.ts
  • src/preflight/RequirementCollector.ts
  • src/formatters/formatter.ts

📝 Walkthrough

Walkthrough

Adds three new format-syntax features to QuickAdd: (1) |time/|datetime flag on VDATE tokens to render a date+time picker; (2) |type:number, |type:checkbox, and |type:text on VALUE tokens to control Obsidian property input types; (3) |multi and |multi:linklist on option-list VALUE tokens to enable multi-select output as a YAML list. Changes span token parsers, new GUI modals (NumberInputPrompt, MultiSuggester), the Formatter base class, CompleteFormatter, preflight scanning, the date picker, YAML scalar quoting utilities, and documentation.

Changes

Enhanced Template Property Types (issue #757)

Layer / File(s) Summary
Token parsing contracts: vdateSyntax and valueSyntax
src/utils/vdateSyntax.ts, src/utils/vdateSyntax.test.ts, src/utils/valueSyntax.ts, src/utils/valueSyntax.test.ts
ParsedVDateOptions gains withTime; parseVDateOptions parses |time/|datetime/|type:datetime flags. ValueInputType expands to number|checkbox|text; ParsedValueToken adds multiSelect and multiEmit; |multi/|multi:linklist parsing enforces constraints (requires option list, incompatible with |case).
YAML context, scalar quoting, and wikilink utilities
src/utils/yamlContext.ts, src/utils/yamlScalarQuoting.ts, src/utils/yamlScalarQuoting.test.ts, src/utils/linkWrap.ts
YamlMatchContext gains isListItemPosition. Adds quoteYamlDouble and shouldQuoteTextScalar helpers for |type:text front-matter safety. Adds idempotent toWikiLink utility.
Date picker time support and VDateInputPrompt wiring
src/gui/date-picker/datePicker.ts, src/gui/date-picker/datePicker.test.ts, src/gui/VDateInputPrompt/VDateInputPrompt.ts
DatePickerOptions gains withTime; createDatePicker adds time-input row, currentTime state, and datetime-ISO emission on Today/day-click/time-change. VDateInputPrompt.Prompt accepts withTime, defers picker mounting via mountDatePicker() after format is derived.
New input modals: NumberInputPrompt and MultiSuggester
src/gui/NumberInputPrompt/NumberInputPrompt.ts, src/gui/MultiSuggester/multiSuggester.ts, src/gui/InputPrompt.ts, src/styles.css
NumberInputPrompt wraps GenericInputPrompt with type=number/step=any input field. MultiSuggester Obsidian modal provides toggle-row multi-select with optional custom-value entry, Skip button, and waitForClose: Promise<string[]>. InputPrompt.factory routes inputTypeOverride=number to NumberInputPrompt. CSS adds time-picker and multi-suggester list styles.
Formatter base: VALUE/VDATE type-aware rendering and multi-select
src/formatters/formatter.ts, src/formatters/formatter-linksection.test.ts
PromptContext gains withTime. Anonymous VALUE replacement YAML-quotes text scalars and comma-joins array values. ensureValueVariableResolved adds |multi branch calling suggestForValueMulti hook with optional toWikiLink wrapping. VDATE defaults format to YYYY-MM-DD HH:mm when withTime. Base suggestForValueMulti default returns [].
CompleteFormatter: suggestForValueMulti and VDATE withTime wiring
src/formatters/completeFormatter.ts, src/formatters/completeFormatter.test.ts
Overrides suggestForValueMulti to invoke MultiSuggester.Suggest with custom/optional/skippable wiring and rethrows cancellation as UserCancelError. VDATE prompt text and VDateInputPrompt.Prompt call forward context.withTime. Adds checkbox handling path in promptForValue.
Preflight pipeline: RequirementCollector, OnePageInputModal, runOnePagePreflight
src/preflight/RequirementCollector.ts, src/preflight/RequirementCollector.test.ts, src/preflight/OnePageInputModal.ts, src/preflight/runOnePagePreflight.ts
FieldType gains "number"; FieldRequirement gains withTime and multiEmit. Collector maps |type:checkbox→dropdown, |type:number"number", |multi→suggester with multiSelect/multiEmit, and records withTime on date requirements. OnePageInputModal renders number fields; passes withTime to createDatePicker. runOnePagePreflight splits comma-joined multi values, reverse-maps display labels, wraps linklist items.
Capture engine warning and documentation
src/engine/CaptureChoiceEngine.ts, docs/docs/FormatSyntax.md, docs/docs/TemplatePropertyTypes.md
CaptureChoiceEngine emits a warning when suppressFrontmatterCollection is active and a {{VALUE:…|multi}} token is detected. Docs add |time, |type:number/checkbox/text, and |multi/|multi:linklist syntax with examples and behavioral notes.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CompleteFormatter
  participant MultiSuggester
  participant Formatter
  participant toWikiLink

  User->>CompleteFormatter: Template with {{VALUE:a,b,c|multi:linklist}}
  CompleteFormatter->>Formatter: ensureValueVariableResolved (multiSelect=true)
  Formatter->>CompleteFormatter: suggestForValueMulti(["a","b","c"])
  CompleteFormatter->>MultiSuggester: Suggest(app, displayItems, items, options)
  MultiSuggester-->>CompleteFormatter: ["b","c"] (selected)
  CompleteFormatter-->>Formatter: ["b","c"]
  Formatter->>toWikiLink: wrap each value (multiEmit=linklist)
  toWikiLink-->>Formatter: ["[[b]]","[[c]]"]
  Formatter->>Formatter: store array in variables map
  Formatter-->>User: YAML list output
Loading
sequenceDiagram
  participant Formatter
  participant parseVDateOptions
  participant VDateInputPrompt
  participant createDatePicker

  Formatter->>parseVDateOptions: parse "tomorrow|time"
  parseVDateOptions-->>Formatter: {withTime: true, defaultValue: "tomorrow", optional: false}
  Formatter->>Formatter: set dateFormat = "YYYY-MM-DD HH:mm"
  Formatter->>VDateInputPrompt: Prompt(app, "Date and time", ..., withTime=true)
  VDateInputPrompt->>createDatePicker: mountDatePicker({withTime: true})
  createDatePicker-->>VDateInputPrompt: picker with time input row rendered
  VDateInputPrompt-->>Formatter: "2025-06-15 14:30"
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • chhoumann/quickadd#1361: Both PRs modify src/formatters/formatter-linksection.test.ts to add the StubFormatter.suggestForFile() stub, indicating direct prerequisite overlap.
  • chhoumann/quickadd#1057: Both PRs extend the VDATE prompt and datePicker.ts to support enhanced picker behavior — the retrieved PR adds a native date picker, while this PR adds withTime datetime mode.
  • chhoumann/quickadd#1336: Both PRs modify the shared VALUE-token resolution pipeline in src/formatters/formatter.ts (ensureValueVariableResolved / replaceVariableInString), with this PR extending it for |multi behavior and the retrieved PR introducing named suggester reuse via |name.

Suggested labels

released

🐇 A rabbit hops through the template maze,
With \|time for dates and \|multi for praise,
Checkboxes tick and numbers now shine,
YAML lists bloom in perfectly neat lines —
From tokens to pickers, the forms all align! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(format): support Obsidian property types in format syntax (#757)' accurately summarizes the main objective of this PR. It highlights the primary feature being added (support for Obsidian property types), the component affected (format syntax), and references the issue number.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chhoumann/757-property-types-feasibility

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 16, 2026

Copy link
Copy Markdown

Deploying quickadd with  Cloudflare Pages  Cloudflare Pages

Latest commit: 43994d5
Status: ✅  Deploy successful!
Preview URL: https://6f3df055.quickadd.pages.dev
Branch Preview URL: https://chhoumann-757-property-types.quickadd.pages.dev

View logs

…rty-types-feasibility

# Conflicts:
#	docs/docs/FormatSyntax.md

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3a281c6032

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/formatters/formatter.ts
Comment thread src/preflight/runOnePagePreflight.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/formatters/formatter.ts (1)

524-547: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Route this warning through the project logger utility.

This touched path still emits through console.warn, which bypasses the repository’s logging pipeline.

As per coding guidelines: **/*.{ts,tsx,js,jsx,svelte} should route logging through the logger utilities for consistent output.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/formatters/formatter.ts` around lines 524 - 547, The
warnOnNamedOptionConflict method uses console.warn() for logging, which bypasses
the project's logging pipeline. According to the coding guidelines for
TypeScript files, all logging must route through the logger utility for
consistent output. Replace the console.warn() call in this method with the
appropriate logger method from the project's logging utilities to ensure the
warning message follows the proper logging pipeline.

Source: Coding guidelines

🧹 Nitpick comments (1)
src/formatters/completeFormatter.test.ts (1)

110-112: ⚡ Quick win

Add focused assertions for the new multi-select/typed VALUE branches.

This mock wiring is in place, but a couple of direct tests would prevent regressions: suggestForValueMulti (done/skip/cancel mapping) and anonymous {{VALUE|type:checkbox}} behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/formatters/completeFormatter.test.ts` around lines 110 - 112, The mock
setup for multiSuggester is in place but direct test coverage is missing for the
new multi-select and typed VALUE branches. Add focused test cases in the
completeFormatter.test.ts file to cover suggestForValueMulti with its
done/skip/cancel mapping behavior, and add a separate test for the anonymous
VALUE syntax with type:checkbox (e.g., {{VALUE|type:checkbox}}). These tests
will prevent regressions on the newly mocked multiSuggesterSuggest
functionality.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/formatters/completeFormatter.ts`:
- Around line 388-400: The checkbox type override (|type:checkbox) is currently
only applied to named VALUE tokens in the promptForVariable path, but anonymous
VALUE tokens (those without a variable name) route through promptForValue
instead. To fix this, add the same checkbox type override logic to the
promptForValue function so that anonymous VALUE tokens with the checkbox
modifier also render the forced true/false picker instead of accepting arbitrary
free text input. Apply the same conditional check for context?.inputTypeOverride
=== "checkbox" and GenericSuggester.Suggest call with the same parameters
(["true", "false"] options and appropriate label) in the promptForValue path.

In `@src/gui/date-picker/datePicker.ts`:
- Around line 101-109: The extractTimeFromIso function currently accepts
out-of-range time values as valid. After the NaN checks for hour and minute
(following line 107), add explicit bounds validation to ensure hour is between 0
and 23 and minute is between 0 and 59. If either value falls outside these
ranges, return null instead of returning the invalid TimeParts object.

In `@src/preflight/RequirementCollector.test.ts`:
- Around line 410-447: The "RequirementCollector property types (`#757`)" describe
block and all its test cases use space indentation, which violates the repo's
formatting policy that requires tab indentation for TypeScript files. Replace
all leading spaces with tabs throughout the entire describe block, including the
run helper function definition and all it() test cases ("maps |type:number to a
number field", "maps |type:checkbox to a true/false dropdown", "maps |multi to a
multi-select suggester", and "carries |multi:linklist and |multi|custom
config"). Ensure the entire block uses consistent tab indentation with LF line
endings.

In `@src/preflight/RequirementCollector.ts`:
- Around line 310-315: The issue is that when a date key is reused across
multiple VDATE occurrences with different time specifications (some with |time
or |datetime), the withTime metadata is only captured on first insertion and not
merged when the same key appears later with |time or |datetime. Fix this by
updating the logic in scanDateTokens to check if a date key already exists in
the requirements collection, and if the current occurrence has withTime=true,
upgrade the existing requirement's withTime property to true rather than
skipping it. This ensures that if any VDATE occurrence for a key includes |time
or |datetime, the final requirement reflects that capability. The fix applies to
the code around the parseVDateOptions call in the provided diff (lines 310-315)
and also to the subsequent handling of the same requirement around lines 324-338
where the requirement is stored or updated.

In `@src/preflight/runOnePagePreflight.ts`:
- Around line 109-115: The current implementation in runOnePagePreflight.ts uses
split(",") to parse multi-select values from a comma-delimited string, which
corrupts any label or custom value containing a comma. Instead of parsing the
comma-delimited string with split(","), modify the flow to accept a structured
multi-value payload as a string[] directly from the modal/suggester path. This
means the upstream modal/suggester should pass the selected values as an array,
and the processing logic should skip the string splitting step entirely,
receiving the values already in the correct structured format. Then apply the
displayToValue mapping and filtering on the array of values as received, rather
than deriving them from comma-splitting.

In `@src/utils/valueSyntax.ts`:
- Around line 293-303: The code is using direct console.warn calls for warning
messages, which violates the repository's logging rules that require all logging
to be routed through the shared logger utility. Replace the two console.warn
calls in the unsupported VALUE type warning and the option-list VALUE token
warning with appropriate logger utility calls, ensuring consistency with the
project's logging pathway. This same pattern also appears in another section of
the file (around lines 512-523) and should be updated there as well.

---

Outside diff comments:
In `@src/formatters/formatter.ts`:
- Around line 524-547: The warnOnNamedOptionConflict method uses console.warn()
for logging, which bypasses the project's logging pipeline. According to the
coding guidelines for TypeScript files, all logging must route through the
logger utility for consistent output. Replace the console.warn() call in this
method with the appropriate logger method from the project's logging utilities
to ensure the warning message follows the proper logging pipeline.

---

Nitpick comments:
In `@src/formatters/completeFormatter.test.ts`:
- Around line 110-112: The mock setup for multiSuggester is in place but direct
test coverage is missing for the new multi-select and typed VALUE branches. Add
focused test cases in the completeFormatter.test.ts file to cover
suggestForValueMulti with its done/skip/cancel mapping behavior, and add a
separate test for the anonymous VALUE syntax with type:checkbox (e.g.,
{{VALUE|type:checkbox}}). These tests will prevent regressions on the newly
mocked multiSuggesterSuggest functionality.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 32e02ca6-1c71-49d7-a1fc-6962d3029da3

📥 Commits

Reviewing files that changed from the base of the PR and between 273e4c0 and 3a281c6.

📒 Files selected for processing (26)
  • docs/docs/FormatSyntax.md
  • docs/docs/TemplatePropertyTypes.md
  • src/engine/CaptureChoiceEngine.ts
  • src/formatters/completeFormatter.test.ts
  • src/formatters/completeFormatter.ts
  • src/formatters/formatter-linksection.test.ts
  • src/formatters/formatter.ts
  • src/gui/InputPrompt.ts
  • src/gui/MultiSuggester/multiSuggester.ts
  • src/gui/NumberInputPrompt/NumberInputPrompt.ts
  • src/gui/VDateInputPrompt/VDateInputPrompt.ts
  • src/gui/date-picker/datePicker.test.ts
  • src/gui/date-picker/datePicker.ts
  • src/preflight/OnePageInputModal.ts
  • src/preflight/RequirementCollector.test.ts
  • src/preflight/RequirementCollector.ts
  • src/preflight/runOnePagePreflight.ts
  • src/styles.css
  • src/utils/linkWrap.ts
  • src/utils/valueSyntax.test.ts
  • src/utils/valueSyntax.ts
  • src/utils/vdateSyntax.test.ts
  • src/utils/vdateSyntax.ts
  • src/utils/yamlContext.ts
  • src/utils/yamlScalarQuoting.test.ts
  • src/utils/yamlScalarQuoting.ts

Comment thread src/formatters/completeFormatter.ts
Comment thread src/gui/date-picker/datePicker.ts
Comment thread src/preflight/RequirementCollector.test.ts
Comment thread src/preflight/RequirementCollector.ts
Comment thread src/preflight/runOnePagePreflight.ts
Comment thread src/utils/valueSyntax.ts
- |type:text now skips the string->structured heuristic, so with the beta flag
  ON a comma/bracket value (`a,b`, `[x]`) is quoted as a string instead of
  being collected into a YAML List (e2e-verified: id: "a,b").
- Anonymous {{VALUE|type:checkbox}} now gets the same forced true/false picker
  as the named form (was free text via promptForValue).
- One-page |multi without |custom drops typed off-list values, matching the
  runtime MultiSuggester (was accepting any typed value).
- extractTimeFromIso rejects out-of-range HH:mm (e.g. 99:99) instead of
  emitting an invalid datetime.
- scanDateTokens merges withTime across repeated VDATE occurrences so a reused
  date with |time on any occurrence renders the time control.

Skipped (with rationale): the comma-inside-a-single-option one-page limitation
(needs an invasive shared-suggester rewrite; documented + the default picker
handles it), console.warn->logger (matches the existing convention in these
pure parser utils), and tab-vs-space in the new test (matches the file's
existing 2-space style).
@chhoumann

Copy link
Copy Markdown
Owner Author

Thanks @coderabbitai — addressed in 43994d5:

Fixed

  • |type:text collected as a List under the beta flag (formatter.ts) — |type:text now skips the string→structured heuristic, so a,b/[x] are quoted as a string instead of becoming a List. e2e-verified (id: "a,b").
  • Anonymous {{VALUE|type:checkbox}} now gets the forced true/false picker (was free text via promptForValue).
  • One-page |multi without |custom now drops typed off-list values, matching the runtime MultiSuggester.
  • extractTimeFromIso rejects out-of-range HH:mm (e.g. 99:99).
  • withTime across repeated {{VDATE}} occurrences is now merged (any |time occurrence upgrades the shared control).

Intentionally not changed (rationale)

  • Comma inside a single |multi option in the one-page form — a correct fix needs an invasive rewrite of the shared one-page text-suggester value model (it stores a ", "-joined string in the <input>, with no per-item array). One-page input is opt-in and the default per-prompt picker handles commas correctly; documented as a known limitation.
  • console.warn → logger in valueSyntax.ts — these are pure, App-free parser utils that already use console.warn throughout (and avoid importing the logger to stay out of import cycles); the new warnings match the surrounding convention.
  • Tabs vs spaces in the new RequirementCollector.test.ts block — it matches the file's existing 2-space style (lint passes); switching only the new block would make the file inconsistent.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@chhoumann: Thanks for the thorough follow-up! All five fixes look well-targeted:

  • The |type:text / beta-flag list bypass and the anonymous checkbox picker fix are the two I was most concerned about — good to hear both are verified end-to-end.
  • extractTimeFromIso range validation is a nice defensive addition.
  • The withTime merge-on-repeat semantics is the right call (upgrading is safe; downgrading would be surprising).

The rationale for the three intentional non-changes all holds:

  • One-page comma limitation — the shared ", "-joined string model makes a clean fix genuinely invasive; documenting it as a known limitation is the right call for now.
  • console.warn in valueSyntax.ts — keeping App-free parsers out of the logger import graph is a good boundary to maintain.
  • 2-space style in RequirementCollector.test.ts — consistent with the existing file; no reason to single out the new block.

Everything looks good. 🐇✨


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

@chhoumann chhoumann merged commit 463ed3e into master Jun 16, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE REQUEST] Improving QuickAdd format syntax compatibility with the new Obsidian properties types (list, checkbox, date, date & time, number) ?

1 participant