fix: BLOCKMENTIONSDATED handles comma dates and 'first of' phrases (#54)#153
fix: BLOCKMENTIONSDATED handles comma dates and 'first of' phrases (#54)#153salmonumbrella wants to merge 1 commit intoRoamJS:mainfrom
Conversation
WalkthroughThis pull request introduces a new utility module for parsing block mention arguments with enhanced date handling. The new Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/utils/core.ts`:
- Around line 133-142: parseBlockMentionsDatedArg currently normalizes "first
of" to "start of" which chrono-node doesn't parse and can return null that later
gets passed into startOfDay/endOfDay; update the parsing and callers by (1)
extending the NLP parser to recognize "start of/beginning of this|next|last
(month|year|week)" (or normalize "start of" to a chrono-friendly phrase like
"beginning of") inside parseNlpDate/addNlpDateParser so phrases like "start of
this month" produce a valid Date, and (2) make callers defensively handle null
by replacing parseBlockMentionsDatedArg(...) with a non-null fallback (e.g.,
parseBlockMentionsDatedArg(startArg, referenceDate) || referenceDate) before
passing into startOfDay/endOfDay; reference symbols: parseBlockMentionsDatedArg,
parseNlpDate, addNlpDateParser, pageTitleToDate, startOfDay, endOfDay.
In `@src/utils/splitSmartBlockArgs.ts`:
- Around line 38-53: The pageRefStack counter is updated even when inside a
command, allowing an unclosed "[[" within a "<%...%>" to leak and block comma
splitting; in the splitSmartBlockArgs logic (variables commandStack,
pageRefStack, afterColon) only increment/decrement pageRefStack when
commandStack === 0 so bracket nesting inside commands is ignored — modify the
branches that handle "[[" and "]]" to check commandStack === 0 before changing
pageRefStack.
- Around line 54-56: The parser drops a leading empty arg because args starts as
[] and the comma handler (inside splitSmartBlockArgs where cur === "," &&
!commandStack && !pageRefStack && prev !== "\\") pushes a new empty slot which
becomes the second arg; to fix, initialize args with a single empty string (args
= [""]) before the main parsing loop (or at start of parsing for the afterColon
segment) so a leading comma produces ["","..."] as intended; leave the existing
comma handler and other logic intact but ensure any code that reinitializes args
preserves the initial [""] seed.
In `@tests/splitSmartBlockArgs.test.ts`:
- Around line 4-75: Add four unit tests for splitSmartBlockArgs to cover the
missing edge cases: (1) an empty afterColon argument ("") should assert []
instead of [""], (2) an escaped comma input like "a\\,b" should return ["a,b"]
to exercise the backslash-escape branch, (3) a leading comma input like ",title"
should assert ["", "title"] (or the expected behavior your implementation
intends) to catch the first-arg-drop bug, and (4) a balanced page ref with an
internal comma and a trailing year token like "[[January 1st, 2023]],2023"
should verify that the page ref remains a single token ("[[January 1st, 2023]]")
and the year stays separate; add these tests alongside the existing ones
referencing splitSmartBlockArgs so they run in the same suite.
- Around line 43-57: The test for "coalesces at most two date tokens for
BLOCKMENTIONSDATED" currently expects a final token of " 2023" (with a leading
space) because coalesceBlockMentionsDatedDates stops after mergedDates === 2 and
forwards the untrimmed remaining token as the format argument; add a short
inline comment in the test (near the expect or the tokens array) explaining that
the leading space is intentional and results from the third date not being
coalesced so future readers won't treat " 2023" as a typo — reference the test
name and the splitSmartBlockArgs call so it's clear which behavior is being
documented.
| const parseBlockMentionsDatedArg = (dateArg: string, referenceDate: Date) => { | ||
| const normalizedArg = dateArg.trim().replace(/^first of\b/i, "start of"); | ||
| const title = | ||
| DAILY_REF_REGEX.exec(normalizedArg)?.[1] || | ||
| DAILY_NOTE_PAGE_TITLE_REGEX.exec(extractTag(normalizedArg))?.[0]; | ||
| return title | ||
| ? window.roamAlphaAPI.util.pageTitleToDate(title) || | ||
| parseNlpDate(normalizedArg, referenceDate) | ||
| : parseNlpDate(normalizedArg, referenceDate); | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
date-fns startOfDay null behavior JavaScript
💡 Result:
In date-fns, startOfDay calls toDate first, then does setHours(0,0,0,0). (app.unpkg.com)
What happens if you pass null?
It depends on the date-fns major version:
-
date-fns v2 (and the v2-era design):
nullis treated as not a valid date, sotoDate(null)returnsInvalid Date, and thereforestartOfDay(null)also yields an invalid date value. (blog.date-fns.org) -
date-fns v4.1.0 (current “latest” on unpkg at the time of this lookup):
toDate(null)ends up doingnew Date(null)viaconstructFrom(...), which produces a valid Date at Unix epoch (timestamp 0), sostartOfDay(null)returns the start of 1970-01-01 in the local timezone. (app.unpkg.com)
Practical takeaway
Don’t rely on null coercion—guard it yourself (or validate with isValid) before calling startOfDay, because the runtime behavior has differed across major versions. (app.unpkg.com)
Citations:
- 1: https://app.unpkg.com/date-fns%404.1.0/files/startOfDay.js
- 2: https://blog.date-fns.org/v2-esm/?utm_source=openai
- 3: https://app.unpkg.com/date-fns%404.1.0/files/toDate.js
- 4: https://app.unpkg.com/date-fns%404.1.0/files/startOfDay.js
🌐 Web query:
chrono-node "start of this month" natural language parsing
💡 Result:
chrono-node doesn’t have a built-in concept like “start of this month” (i.e., normalize to day 1 @ 00:00), but it’s designed to be extended: you can clone a parser (e.g. chrono.casual.clone()) and push a custom parser (or a refiner) to recognize that phrase and return the components you want. (npmjs.com)
Option A: Add a custom parser for “start of this month”
import * as chrono from "chrono-node";
const custom = chrono.casual.clone();
custom.parsers.push({
pattern: () => /\bstart of (this|current) month\b/i,
extract: (context, match) => {
const ref = context.refDate; // the reference date chrono is parsing relative to
return {
year: ref.getFullYear(),
month: ref.getMonth() + 1, // chrono months are 1-12
day: 1,
hour: 0,
minute: 0,
second: 0,
millisecond: 0,
};
},
});
const d = custom.parseDate("start of this month"); // -> Date at local 00:00 on the 1stThis follows chrono’s documented extension pattern (clone + parsers.push(...)). (npmjs.com)
Option B: Parse “this month”, then post-process
If you’re okay with post-processing, parse something like "this month" and then set the returned Date to the 1st at midnight in your own code (using JS new Date(y, m, 1)), rather than teaching chrono the phrase. (Chrono exposes parseDate / parse and ParsedComponents.date() to get a Date you can adjust.) (npmjs.com)
Citations:
- 1: https://www.npmjs.com/package/chrono-node?utm_source=openai
- 2: https://www.npmjs.com/package/chrono-node?utm_source=openai
- 3: https://www.npmjs.com/package/chrono-node?utm_source=openai
🏁 Script executed:
cat -n src/utils/core.ts | sed -n '1230,1240p'Repository: RoamJS/smartblocks
Length of output: 619
🏁 Script executed:
grep -n "const parseNlpDate" src/utils/core.ts -A 10Repository: RoamJS/smartblocks
Length of output: 44
🏁 Script executed:
cat package.json | grep -A 2 -B 2 '"date-fns"'Repository: RoamJS/smartblocks
Length of output: 44
🏁 Script executed:
rg "parseNlpDate" src/utils/core.ts -A 5 -B 2Repository: RoamJS/smartblocks
Length of output: 5975
🏁 Script executed:
fd package.jsonRepository: RoamJS/smartblocks
Length of output: 74
🏁 Script executed:
rg "date-fns" package.jsonRepository: RoamJS/smartblocks
Length of output: 44
🏁 Script executed:
rg "addNlpDateParser" src/utils/core.tsRepository: RoamJS/smartblocks
Length of output: 100
🏁 Script executed:
head -50 package.jsonRepository: RoamJS/smartblocks
Length of output: 835
🏁 Script executed:
rg "addNlpDateParser" src/utils/core.ts -A 20 -B 2Repository: RoamJS/smartblocks
Length of output: 1824
🏁 Script executed:
rg "addNlpDateParser" src/utils/core.ts -A 50 | head -100Repository: RoamJS/smartblocks
Length of output: 3272
parseBlockMentionsDatedArg returns null when date parsing fails, and the "first of" → "start of" normalization is unsupported.
1. Missing "start of" parser: Line 137 replaces "first of" → "start of" (e.g., "first of this month" becomes "start of this month"), but chrono-node has no built-in parser for "start of" phrases. The custom parser added via addNlpDateParser only handles the DBOM/DEOM format, not natural language "start of" expressions. This means the normalized phrase will fail to parse, and parseNlpDate will return null.
2. Null propagation into startOfDay/endOfDay: When pageTitleToDate and parseNlpDate both fail, parseBlockMentionsDatedArg returns null. The guards at lines 1233 and 1237 check if startArg and endArg are truthy, but they do not guard the return value of parseBlockMentionsDatedArg. A null result propagates directly into startOfDay(null) and endOfDay(null). In date-fns v4, new Date(null) coerces to Unix epoch (1970-01-01), which will silently filter results to that date instead of failing loudly.
Fixes:
- Add a custom NLP parser for "start of this month/year/week" patterns, or adjust the normalization to a phrase chrono-node understands (e.g., "beginning of this month").
- Guard the return value:
parseBlockMentionsDatedArg(startArg, referenceDate) || new Date()before passing tostartOfDay/endOfDay.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/utils/core.ts` around lines 133 - 142, parseBlockMentionsDatedArg
currently normalizes "first of" to "start of" which chrono-node doesn't parse
and can return null that later gets passed into startOfDay/endOfDay; update the
parsing and callers by (1) extending the NLP parser to recognize "start
of/beginning of this|next|last (month|year|week)" (or normalize "start of" to a
chrono-friendly phrase like "beginning of") inside parseNlpDate/addNlpDateParser
so phrases like "start of this month" produce a valid Date, and (2) make callers
defensively handle null by replacing parseBlockMentionsDatedArg(...) with a
non-null fallback (e.g., parseBlockMentionsDatedArg(startArg, referenceDate) ||
referenceDate) before passing into startOfDay/endOfDay; reference symbols:
parseBlockMentionsDatedArg, parseNlpDate, addNlpDateParser, pageTitleToDate,
startOfDay, endOfDay.
| let commandStack = 0; | ||
| let pageRefStack = 0; | ||
| const args = [] as string[]; | ||
| for (let i = 0; i < afterColon.length; i += 1) { | ||
| const cur = afterColon[i]; | ||
| const prev = afterColon[i - 1]; | ||
| const next = afterColon[i + 1]; | ||
| if (cur === "%" && prev === "<") { | ||
| commandStack += 1; | ||
| } else if (cur === "%" && next === ">" && commandStack) { | ||
| commandStack -= 1; | ||
| } else if (cur === "[" && next === "[") { | ||
| pageRefStack += 1; | ||
| } else if (cur === "]" && prev === "]" && pageRefStack) { | ||
| pageRefStack -= 1; | ||
| } |
There was a problem hiding this comment.
pageRefStack can leak past a <%...%> command boundary when the command contains an unclosed [[.
The else if chain updates pageRefStack regardless of commandStack, meaning an unclosed [[ inside a nested command leaves pageRefStack > 0 after commandStack returns to zero. Any comma that follows the nested command will then be swallowed instead of acting as an argument separator.
Concrete trace for afterColon = "<%CMD:[[page%>,nextArg":
<%→commandStack = 1[[→pageRefStack = 1← happens even whilecommandStack > 0%>→commandStack = 0;pageRefStackstays at 1,→ not split (pageRefStack = 1)- Result:
["<%CMD:[[page%>,nextArg"]instead of["<%CMD:[[page%>", "nextArg"]
This only triggers on malformed input, but the fix is straightforward — only modify pageRefStack when commandStack === 0:
🛡️ Proposed fix
if (cur === "%" && prev === "<") {
commandStack += 1;
} else if (cur === "%" && next === ">" && commandStack) {
commandStack -= 1;
- } else if (cur === "[" && next === "[") {
- pageRefStack += 1;
- } else if (cur === "]" && prev === "]" && pageRefStack) {
- pageRefStack -= 1;
+ } else if (!commandStack) {
+ if (cur === "[" && next === "[") {
+ pageRefStack += 1;
+ } else if (cur === "]" && prev === "]" && pageRefStack) {
+ pageRefStack -= 1;
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let commandStack = 0; | |
| let pageRefStack = 0; | |
| const args = [] as string[]; | |
| for (let i = 0; i < afterColon.length; i += 1) { | |
| const cur = afterColon[i]; | |
| const prev = afterColon[i - 1]; | |
| const next = afterColon[i + 1]; | |
| if (cur === "%" && prev === "<") { | |
| commandStack += 1; | |
| } else if (cur === "%" && next === ">" && commandStack) { | |
| commandStack -= 1; | |
| } else if (cur === "[" && next === "[") { | |
| pageRefStack += 1; | |
| } else if (cur === "]" && prev === "]" && pageRefStack) { | |
| pageRefStack -= 1; | |
| } | |
| let commandStack = 0; | |
| let pageRefStack = 0; | |
| const args = [] as string[]; | |
| for (let i = 0; i < afterColon.length; i += 1) { | |
| const cur = afterColon[i]; | |
| const prev = afterColon[i - 1]; | |
| const next = afterColon[i + 1]; | |
| if (cur === "%" && prev === "<") { | |
| commandStack += 1; | |
| } else if (cur === "%" && next === ">" && commandStack) { | |
| commandStack -= 1; | |
| } else if (!commandStack) { | |
| if (cur === "[" && next === "[") { | |
| pageRefStack += 1; | |
| } else if (cur === "]" && prev === "]" && pageRefStack) { | |
| pageRefStack -= 1; | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/utils/splitSmartBlockArgs.ts` around lines 38 - 53, The pageRefStack
counter is updated even when inside a command, allowing an unclosed "[[" within
a "<%...%>" to leak and block comma splitting; in the splitSmartBlockArgs logic
(variables commandStack, pageRefStack, afterColon) only increment/decrement
pageRefStack when commandStack === 0 so bracket nesting inside commands is
ignored — modify the branches that handle "[[" and "]]" to check commandStack
=== 0 before changing pageRefStack.
| if (cur === "," && !commandStack && !pageRefStack && prev !== "\\") { | ||
| args.push(""); | ||
| continue; |
There was a problem hiding this comment.
Leading comma silently drops the first argument slot.
args is initialized as []. When afterColon begins with ,, args.push("") (the handler for a comma) pushes the only element, but it represents the second argument's slot, not the first. The subsequent character then fills args[0], permanently losing the first empty argument.
afterColon = ",title" → ["title"] // expects ["", "title"]
For BLOCKMENTIONSDATED this shifts every positional arg left by one (title → limit, startDate → title, …).
🛡️ Proposed fix
if (cur === "," && !commandStack && !pageRefStack && prev !== "\\") {
+ if (!args.length) args.push(""); // ensure first arg slot exists
args.push("");
continue;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (cur === "," && !commandStack && !pageRefStack && prev !== "\\") { | |
| args.push(""); | |
| continue; | |
| if (cur === "," && !commandStack && !pageRefStack && prev !== "\\") { | |
| if (!args.length) args.push(""); // ensure first arg slot exists | |
| args.push(""); | |
| continue; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/utils/splitSmartBlockArgs.ts` around lines 54 - 56, The parser drops a
leading empty arg because args starts as [] and the comma handler (inside
splitSmartBlockArgs where cur === "," && !commandStack && !pageRefStack && prev
!== "\\") pushes a new empty slot which becomes the second arg; to fix,
initialize args with a single empty string (args = [""]) before the main parsing
loop (or at start of parsing for the afterColon segment) so a leading comma
produces ["","..."] as intended; leave the existing comma handler and other
logic intact but ensure any code that reinitializes args preserves the initial
[""] seed.
| test("splits nested smartblock commands as a single argument", () => { | ||
| expect( | ||
| splitSmartBlockArgs("ANYCOMMAND", "one,<%RANDOMNUMBER:1,10%>,two") | ||
| ).toEqual(["one", "<%RANDOMNUMBER:1,10%>", "two"]); | ||
| }); | ||
|
|
||
| test("preserves commas in daily note page references", () => { | ||
| expect( | ||
| splitSmartBlockArgs( | ||
| "BLOCKMENTIONSDATED", | ||
| "10,DONE,[[January 24th, 2023]],[[January 1st, 2023]]" | ||
| ) | ||
| ).toEqual(["10", "DONE", "[[January 24th, 2023]]", "[[January 1st, 2023]]"]); | ||
| }); | ||
|
|
||
| test("coalesces month-day-year date tokens for BLOCKMENTIONSDATED", () => { | ||
| expect( | ||
| splitSmartBlockArgs( | ||
| "BLOCKMENTIONSDATED", | ||
| "10,DONE,February 1, 2023,February 24, 2023,DESC" | ||
| ) | ||
| ).toEqual(["10", "DONE", "February 1, 2023", "February 24, 2023", "DESC"]); | ||
| }); | ||
|
|
||
| test("handles unclosed [[ gracefully by treating rest as single arg", () => { | ||
| expect( | ||
| splitSmartBlockArgs("BLOCKMENTIONSDATED", "10,DONE,[[January 24th") | ||
| ).toEqual(["10", "DONE", "[[January 24th"]); | ||
| }); | ||
|
|
||
| test("preserves commas inside nested page references", () => { | ||
| expect( | ||
| splitSmartBlockArgs( | ||
| "BLOCKMENTIONSDATED", | ||
| "10,DONE,[[January 24th, 2023]],today" | ||
| ) | ||
| ).toEqual(["10", "DONE", "[[January 24th, 2023]]", "today"]); | ||
| }); | ||
|
|
||
| test("coalesces at most two date tokens for BLOCKMENTIONSDATED", () => { | ||
| expect( | ||
| splitSmartBlockArgs( | ||
| "BLOCKMENTIONSDATED", | ||
| "10,DONE,January 1, 2023,February 1, 2023,March 1, 2023" | ||
| ) | ||
| ).toEqual([ | ||
| "10", | ||
| "DONE", | ||
| "January 1, 2023", | ||
| "February 1, 2023", | ||
| "March 1", | ||
| " 2023", | ||
| ]); | ||
| }); | ||
|
|
||
| test("does not coalesce date tokens for non-BLOCKMENTIONSDATED commands", () => { | ||
| expect( | ||
| splitSmartBlockArgs("ANYCOMMAND", "January 1, 2023") | ||
| ).toEqual(["January 1", " 2023"]); | ||
| }); | ||
|
|
||
| test("unclosed [[ in non-BLOCKMENTIONSDATED treats remaining as single arg", () => { | ||
| expect( | ||
| splitSmartBlockArgs("ANYCOMMAND", "one,[[unclosed,two,three") | ||
| ).toEqual(["one", "[[unclosed,two,three"]); | ||
| }); | ||
|
|
||
| test("balanced [[ ]] followed by normal args splits correctly", () => { | ||
| expect( | ||
| splitSmartBlockArgs("ANYCOMMAND", "[[page ref]],normal,arg") | ||
| ).toEqual(["[[page ref]]", "normal", "arg"]); | ||
| }); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Missing edge-case test coverage.
The suite covers the happy paths well, but several boundary conditions are absent:
| Scenario | Why it matters |
|---|---|
Empty afterColon ("") |
Should return []; verifies the caller doesn't receive [""] |
Escaped comma ("a\\,b") |
The backslash-escape path at lines 57–58 of splitSmartBlockArgs.ts is untested |
Leading comma (",title") |
Exercises the known first-arg-drop bug (see related comment on splitSmartBlockArgs.ts) |
Balanced [[...]] with comma inside and trailing year token |
Ensures [[January 1st, 2023]] is not coalesced when it's already one token (the coalescence regex only matches bare "Month Day") |
Would you like me to draft the missing test cases?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/splitSmartBlockArgs.test.ts` around lines 4 - 75, Add four unit tests
for splitSmartBlockArgs to cover the missing edge cases: (1) an empty afterColon
argument ("") should assert [] instead of [""], (2) an escaped comma input like
"a\\,b" should return ["a,b"] to exercise the backslash-escape branch, (3) a
leading comma input like ",title" should assert ["", "title"] (or the expected
behavior your implementation intends) to catch the first-arg-drop bug, and (4) a
balanced page ref with an internal comma and a trailing year token like
"[[January 1st, 2023]],2023" should verify that the page ref remains a single
token ("[[January 1st, 2023]]") and the year stays separate; add these tests
alongside the existing ones referencing splitSmartBlockArgs so they run in the
same suite.
| test("coalesces at most two date tokens for BLOCKMENTIONSDATED", () => { | ||
| expect( | ||
| splitSmartBlockArgs( | ||
| "BLOCKMENTIONSDATED", | ||
| "10,DONE,January 1, 2023,February 1, 2023,March 1, 2023" | ||
| ) | ||
| ).toEqual([ | ||
| "10", | ||
| "DONE", | ||
| "January 1, 2023", | ||
| "February 1, 2023", | ||
| "March 1", | ||
| " 2023", | ||
| ]); | ||
| }); |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Third-date coalescence limit behavior is correctly documented, but the " 2023" leading space deserves a comment.
The test asserts " 2023" (with leading space) as the 6th token when a third date is supplied. This is technically correct — coalesceBlockMentionsDatedDates stops after mergedDates === 2 and passes the raw, un-trimmed " 2023" token as the format argument of BLOCKMENTIONSDATED. Adding an inline comment makes the intent explicit so future readers don't mistake the leading space for a typo:
💡 Suggested comment
).toEqual([
"10",
"DONE",
"January 1, 2023",
"February 1, 2023",
- "March 1",
- " 2023",
+ "March 1", // mergedDates === 2, so 3rd date is not coalesced...
+ " 2023", // ...and the raw " 2023" token retains its leading space
]);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| test("coalesces at most two date tokens for BLOCKMENTIONSDATED", () => { | |
| expect( | |
| splitSmartBlockArgs( | |
| "BLOCKMENTIONSDATED", | |
| "10,DONE,January 1, 2023,February 1, 2023,March 1, 2023" | |
| ) | |
| ).toEqual([ | |
| "10", | |
| "DONE", | |
| "January 1, 2023", | |
| "February 1, 2023", | |
| "March 1", | |
| " 2023", | |
| ]); | |
| }); | |
| test("coalesces at most two date tokens for BLOCKMENTIONSDATED", () => { | |
| expect( | |
| splitSmartBlockArgs( | |
| "BLOCKMENTIONSDATED", | |
| "10,DONE,January 1, 2023,February 1, 2023,March 1, 2023" | |
| ) | |
| ).toEqual([ | |
| "10", | |
| "DONE", | |
| "January 1, 2023", | |
| "February 1, 2023", | |
| "March 1", // mergedDates === 2, so 3rd date is not coalesced... | |
| " 2023", // ...and the raw " 2023" token retains its leading space | |
| ]); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/splitSmartBlockArgs.test.ts` around lines 43 - 57, The test for
"coalesces at most two date tokens for BLOCKMENTIONSDATED" currently expects a
final token of " 2023" (with a leading space) because
coalesceBlockMentionsDatedDates stops after mergedDates === 2 and forwards the
untrimmed remaining token as the format argument; add a short inline comment in
the test (near the expect or the tokens array) explaining that the leading space
is intentional and results from the third date not being coalesced so future
readers won't treat " 2023" as a typo — reference the test name and the
splitSmartBlockArgs call so it's clear which behavior is being documented.
Summary
Issue
Closes #54
Summary by CodeRabbit
New Features
Improvements
Tests