@md2do/core 0.2.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/coverage/coverage-final.json +6 -5
  3. package/coverage/index.html +52 -37
  4. package/coverage/lcov-report/index.html +52 -37
  5. package/coverage/lcov-report/src/filters/index.html +1 -1
  6. package/coverage/lcov-report/src/filters/index.ts.html +1 -1
  7. package/coverage/lcov-report/src/index.html +5 -5
  8. package/coverage/lcov-report/src/index.ts.html +13 -4
  9. package/coverage/lcov-report/src/parser/index.html +17 -17
  10. package/coverage/lcov-report/src/parser/index.ts.html +181 -13
  11. package/coverage/lcov-report/src/parser/patterns.ts.html +18 -9
  12. package/coverage/lcov-report/src/scanner/index.html +15 -15
  13. package/coverage/lcov-report/src/scanner/index.ts.html +83 -8
  14. package/coverage/lcov-report/src/sorting/index.html +1 -1
  15. package/coverage/lcov-report/src/sorting/index.ts.html +1 -1
  16. package/coverage/lcov-report/src/utils/dates.ts.html +169 -25
  17. package/coverage/lcov-report/src/utils/id.ts.html +1 -1
  18. package/coverage/lcov-report/src/utils/index.html +19 -19
  19. package/coverage/lcov-report/src/warnings/filter.ts.html +364 -0
  20. package/coverage/lcov-report/src/warnings/index.html +116 -0
  21. package/coverage/lcov-report/src/writer/index.html +1 -1
  22. package/coverage/lcov-report/src/writer/index.ts.html +1 -1
  23. package/coverage/lcov.info +760 -512
  24. package/coverage/src/filters/index.html +1 -1
  25. package/coverage/src/filters/index.ts.html +1 -1
  26. package/coverage/src/index.html +5 -5
  27. package/coverage/src/index.ts.html +13 -4
  28. package/coverage/src/parser/index.html +17 -17
  29. package/coverage/src/parser/index.ts.html +181 -13
  30. package/coverage/src/parser/patterns.ts.html +18 -9
  31. package/coverage/src/scanner/index.html +15 -15
  32. package/coverage/src/scanner/index.ts.html +83 -8
  33. package/coverage/src/sorting/index.html +1 -1
  34. package/coverage/src/sorting/index.ts.html +1 -1
  35. package/coverage/src/utils/dates.ts.html +169 -25
  36. package/coverage/src/utils/id.ts.html +1 -1
  37. package/coverage/src/utils/index.html +19 -19
  38. package/coverage/src/warnings/filter.ts.html +364 -0
  39. package/coverage/src/warnings/index.html +116 -0
  40. package/coverage/src/writer/index.html +1 -1
  41. package/coverage/src/writer/index.ts.html +1 -1
  42. package/dist/index.d.mts +103 -12
  43. package/dist/index.d.ts +103 -12
  44. package/dist/index.js +125 -11
  45. package/dist/index.mjs +125 -12
  46. package/package.json +1 -1
  47. package/src/index.ts +3 -0
  48. package/src/parser/index.ts +61 -5
  49. package/src/parser/patterns.ts +8 -5
  50. package/src/scanner/index.ts +25 -0
  51. package/src/types/index.ts +35 -2
  52. package/src/utils/dates.ts +58 -10
  53. package/src/warnings/filter.ts +93 -0
@@ -23,16 +23,16 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">100% </span>
26
+ <span class="strong">97.22% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>191/191</span>
28
+ <span class='fraction'>210/216</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">100% </span>
33
+ <span class="strong">79.31% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>23/23</span>
35
+ <span class='fraction'>23/29</span>
36
36
  </div>
37
37
 
38
38
 
@@ -44,9 +44,9 @@
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">100% </span>
47
+ <span class="strong">97.22% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>191/191</span>
49
+ <span class='fraction'>210/216</span>
50
50
  </div>
51
51
 
52
52
 
@@ -254,7 +254,32 @@
254
254
  <a name='L189'></a><a href='#L189'>189</a>
255
255
  <a name='L190'></a><a href='#L190'>190</a>
256
256
  <a name='L191'></a><a href='#L191'>191</a>
257
- <a name='L192'></a><a href='#L192'>192</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
257
+ <a name='L192'></a><a href='#L192'>192</a>
258
+ <a name='L193'></a><a href='#L193'>193</a>
259
+ <a name='L194'></a><a href='#L194'>194</a>
260
+ <a name='L195'></a><a href='#L195'>195</a>
261
+ <a name='L196'></a><a href='#L196'>196</a>
262
+ <a name='L197'></a><a href='#L197'>197</a>
263
+ <a name='L198'></a><a href='#L198'>198</a>
264
+ <a name='L199'></a><a href='#L199'>199</a>
265
+ <a name='L200'></a><a href='#L200'>200</a>
266
+ <a name='L201'></a><a href='#L201'>201</a>
267
+ <a name='L202'></a><a href='#L202'>202</a>
268
+ <a name='L203'></a><a href='#L203'>203</a>
269
+ <a name='L204'></a><a href='#L204'>204</a>
270
+ <a name='L205'></a><a href='#L205'>205</a>
271
+ <a name='L206'></a><a href='#L206'>206</a>
272
+ <a name='L207'></a><a href='#L207'>207</a>
273
+ <a name='L208'></a><a href='#L208'>208</a>
274
+ <a name='L209'></a><a href='#L209'>209</a>
275
+ <a name='L210'></a><a href='#L210'>210</a>
276
+ <a name='L211'></a><a href='#L211'>211</a>
277
+ <a name='L212'></a><a href='#L212'>212</a>
278
+ <a name='L213'></a><a href='#L213'>213</a>
279
+ <a name='L214'></a><a href='#L214'>214</a>
280
+ <a name='L215'></a><a href='#L215'>215</a>
281
+ <a name='L216'></a><a href='#L216'>216</a>
282
+ <a name='L217'></a><a href='#L217'>217</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
258
283
  <span class="cline-any cline-yes">1x</span>
259
284
  <span class="cline-any cline-yes">1x</span>
260
285
  <span class="cline-any cline-yes">1x</span>
@@ -321,6 +346,15 @@
321
346
  <span class="cline-any cline-yes">1x</span>
322
347
  <span class="cline-any cline-yes">1x</span>
323
348
  <span class="cline-any cline-yes">1x</span>
349
+ <span class="cline-any cline-yes">1x</span>
350
+ <span class="cline-any cline-yes">44x</span>
351
+ <span class="cline-any cline-yes">44x</span>
352
+ <span class="cline-any cline-yes">44x</span>
353
+ <span class="cline-any cline-yes">44x</span>
354
+ <span class="cline-any cline-yes">44x</span>
355
+ <span class="cline-any cline-yes">44x</span>
356
+ <span class="cline-any cline-yes">44x</span>
357
+ <span class="cline-any cline-yes">44x</span>
324
358
  <span class="cline-any cline-yes">44x</span>
325
359
  <span class="cline-any cline-yes">44x</span>
326
360
  <span class="cline-any cline-yes">44x</span>
@@ -341,6 +375,14 @@
341
375
  <span class="cline-any cline-yes">44x</span>
342
376
  <span class="cline-any cline-yes">44x</span>
343
377
  <span class="cline-any cline-yes">44x</span>
378
+ <span class="cline-any cline-no">&nbsp;</span>
379
+ <span class="cline-any cline-no">&nbsp;</span>
380
+ <span class="cline-any cline-yes">44x</span>
381
+ <span class="cline-any cline-no">&nbsp;</span>
382
+ <span class="cline-any cline-no">&nbsp;</span>
383
+ <span class="cline-any cline-yes">44x</span>
384
+ <span class="cline-any cline-no">&nbsp;</span>
385
+ <span class="cline-any cline-no">&nbsp;</span>
344
386
  <span class="cline-any cline-yes">44x</span>
345
387
  <span class="cline-any cline-yes">44x</span>
346
388
  <span class="cline-any cline-yes">44x</span>
@@ -375,6 +417,10 @@
375
417
  <span class="cline-any cline-yes">5x</span>
376
418
  <span class="cline-any cline-yes">5x</span>
377
419
  <span class="cline-any cline-yes">5x</span>
420
+ <span class="cline-any cline-yes">5x</span>
421
+ <span class="cline-any cline-yes">5x</span>
422
+ <span class="cline-any cline-yes">5x</span>
423
+ <span class="cline-any cline-yes">5x</span>
378
424
  <span class="cline-any cline-yes">18x</span>
379
425
  <span class="cline-any cline-yes">13x</span>
380
426
  <span class="cline-any cline-yes">13x</span>
@@ -435,6 +481,10 @@
435
481
  <span class="cline-any cline-yes">1x</span>
436
482
  <span class="cline-any cline-yes">1x</span>
437
483
  <span class="cline-any cline-yes">1x</span>
484
+ <span class="cline-any cline-yes">1x</span>
485
+ <span class="cline-any cline-yes">1x</span>
486
+ <span class="cline-any cline-yes">1x</span>
487
+ <span class="cline-any cline-yes">1x</span>
438
488
  <span class="cline-any cline-yes">2x</span>
439
489
  <span class="cline-any cline-yes">9x</span>
440
490
  <span class="cline-any cline-yes">9x</span>
@@ -509,11 +559,17 @@ export class MarkdownScanner {
509
559
  *
510
560
  * @param filePath - Relative file path (for context extraction)
511
561
  * @param content - File content as string
562
+ * @param options - Optional scanner options including workday config
512
563
  * @returns Object containing tasks and warnings
513
564
  */
514
565
  scanFile(
515
566
  filePath: string,
516
567
  content: string,
568
+ options?: {
569
+ workdayStartTime?: string;
570
+ workdayEndTime?: string;
571
+ defaultDueTime?: 'start' | 'end';
572
+ },
517
573
  ): {
518
574
  tasks: Task[];
519
575
  warnings: Warning[];
@@ -532,6 +588,17 @@ export class MarkdownScanner {
532
588
  &nbsp;
533
589
  const person = extractPersonFromFilename(filePath);
534
590
  if (person !== undefined) context.person = person;
591
+ &nbsp;
592
+ // Add workday config to context if provided
593
+ if (<span class="branch-0 cbranch-no" title="branch not covered" >options?.workdayStartTime) <span class="branch-0 cbranch-no" title="branch not covered" >{</span></span>
594
+ <span class="cstat-no" title="statement not covered" > context.workdayStartTime = options.workdayStartTime;</span>
595
+ <span class="cstat-no" title="statement not covered" > }</span>
596
+ if (<span class="branch-0 cbranch-no" title="branch not covered" >options?.workdayEndTime) <span class="branch-0 cbranch-no" title="branch not covered" >{</span></span>
597
+ <span class="cstat-no" title="statement not covered" > context.workdayEndTime = options.workdayEndTime;</span>
598
+ <span class="cstat-no" title="statement not covered" > }</span>
599
+ if (<span class="branch-0 cbranch-no" title="branch not covered" >options?.defaultDueTime) <span class="branch-0 cbranch-no" title="branch not covered" >{</span></span>
600
+ <span class="cstat-no" title="statement not covered" > context.defaultDueTime = options.defaultDueTime;</span>
601
+ <span class="cstat-no" title="statement not covered" > }</span>
535
602
  &nbsp;
536
603
  // Process file line by line
537
604
  const lines = content.split('\n');
@@ -561,9 +628,13 @@ export class MarkdownScanner {
561
628
  const existing = todoistIds.get(result.task.todoistId);
562
629
  if (existing) {
563
630
  warnings.push({
631
+ severity: 'error',
632
+ source: 'md2do',
633
+ ruleId: 'duplicate-todoist-id',
564
634
  file: filePath,
565
635
  line: lineNumber,
566
636
  text: result.task.text,
637
+ message: `Duplicate Todoist ID [todoist:${result.task.todoistId}]. Also found at ${existing.file}:${existing.line}.`,
567
638
  reason: `Duplicate Todoist ID [todoist:${result.task.todoistId}]. Also found at ${existing.file}:${existing.line}.`,
568
639
  });
569
640
  } else {
@@ -615,9 +686,13 @@ export class MarkdownScanner {
615
686
  // Only add warning if duplicate is in a different file
616
687
  // (same-file duplicates are already caught by scanFile)
617
688
  allWarnings.push({
689
+ severity: 'error',
690
+ source: 'md2do',
691
+ ruleId: 'duplicate-todoist-id',
618
692
  file: task.file,
619
693
  line: task.line,
620
694
  text: task.text,
695
+ message: `Duplicate Todoist ID [todoist:${task.todoistId}] across files. Also found at ${existing.file}:${existing.line}.`,
621
696
  reason: `Duplicate Todoist ID [todoist:${task.todoistId}] across files. Also found at ${existing.file}:${existing.line}.`,
622
697
  });
623
698
  } else if (!existing) {
@@ -643,7 +718,7 @@ export class MarkdownScanner {
643
718
  <div class='footer quiet pad2 space-top1 center small'>
644
719
  Code coverage generated by
645
720
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
646
- at 2026-01-26T03:50:53.066Z
721
+ at 2026-02-05T05:58:13.697Z
647
722
  </div>
648
723
  <script src="../../prettify.js"></script>
649
724
  <script>
@@ -101,7 +101,7 @@
101
101
  <div class='footer quiet pad2 space-top1 center small'>
102
102
  Code coverage generated by
103
103
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
104
- at 2026-01-26T03:50:53.066Z
104
+ at 2026-02-05T05:58:13.697Z
105
105
  </div>
106
106
  <script src="../../prettify.js"></script>
107
107
  <script>
@@ -721,7 +721,7 @@ export function reverse(comparator: TaskComparator): TaskComparator {
721
721
  <div class='footer quiet pad2 space-top1 center small'>
722
722
  Code coverage generated by
723
723
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
724
- at 2026-01-26T03:50:53.066Z
724
+ at 2026-02-05T05:58:13.697Z
725
725
  </div>
726
726
  <script src="../../prettify.js"></script>
727
727
  <script>
@@ -23,30 +23,30 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">100% </span>
26
+ <span class="strong">88.7% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>138/138</span>
28
+ <span class='fraction'>165/186</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">100% </span>
33
+ <span class="strong">96% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>27/27</span>
35
+ <span class='fraction'>24/25</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">100% </span>
40
+ <span class="strong">75% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>3/3</span>
42
+ <span class='fraction'>3/4</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">100% </span>
47
+ <span class="strong">88.7% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>138/138</span>
49
+ <span class='fraction'>165/186</span>
50
50
  </div>
51
51
 
52
52
 
@@ -201,7 +201,55 @@
201
201
  <a name='L136'></a><a href='#L136'>136</a>
202
202
  <a name='L137'></a><a href='#L137'>137</a>
203
203
  <a name='L138'></a><a href='#L138'>138</a>
204
- <a name='L139'></a><a href='#L139'>139</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
204
+ <a name='L139'></a><a href='#L139'>139</a>
205
+ <a name='L140'></a><a href='#L140'>140</a>
206
+ <a name='L141'></a><a href='#L141'>141</a>
207
+ <a name='L142'></a><a href='#L142'>142</a>
208
+ <a name='L143'></a><a href='#L143'>143</a>
209
+ <a name='L144'></a><a href='#L144'>144</a>
210
+ <a name='L145'></a><a href='#L145'>145</a>
211
+ <a name='L146'></a><a href='#L146'>146</a>
212
+ <a name='L147'></a><a href='#L147'>147</a>
213
+ <a name='L148'></a><a href='#L148'>148</a>
214
+ <a name='L149'></a><a href='#L149'>149</a>
215
+ <a name='L150'></a><a href='#L150'>150</a>
216
+ <a name='L151'></a><a href='#L151'>151</a>
217
+ <a name='L152'></a><a href='#L152'>152</a>
218
+ <a name='L153'></a><a href='#L153'>153</a>
219
+ <a name='L154'></a><a href='#L154'>154</a>
220
+ <a name='L155'></a><a href='#L155'>155</a>
221
+ <a name='L156'></a><a href='#L156'>156</a>
222
+ <a name='L157'></a><a href='#L157'>157</a>
223
+ <a name='L158'></a><a href='#L158'>158</a>
224
+ <a name='L159'></a><a href='#L159'>159</a>
225
+ <a name='L160'></a><a href='#L160'>160</a>
226
+ <a name='L161'></a><a href='#L161'>161</a>
227
+ <a name='L162'></a><a href='#L162'>162</a>
228
+ <a name='L163'></a><a href='#L163'>163</a>
229
+ <a name='L164'></a><a href='#L164'>164</a>
230
+ <a name='L165'></a><a href='#L165'>165</a>
231
+ <a name='L166'></a><a href='#L166'>166</a>
232
+ <a name='L167'></a><a href='#L167'>167</a>
233
+ <a name='L168'></a><a href='#L168'>168</a>
234
+ <a name='L169'></a><a href='#L169'>169</a>
235
+ <a name='L170'></a><a href='#L170'>170</a>
236
+ <a name='L171'></a><a href='#L171'>171</a>
237
+ <a name='L172'></a><a href='#L172'>172</a>
238
+ <a name='L173'></a><a href='#L173'>173</a>
239
+ <a name='L174'></a><a href='#L174'>174</a>
240
+ <a name='L175'></a><a href='#L175'>175</a>
241
+ <a name='L176'></a><a href='#L176'>176</a>
242
+ <a name='L177'></a><a href='#L177'>177</a>
243
+ <a name='L178'></a><a href='#L178'>178</a>
244
+ <a name='L179'></a><a href='#L179'>179</a>
245
+ <a name='L180'></a><a href='#L180'>180</a>
246
+ <a name='L181'></a><a href='#L181'>181</a>
247
+ <a name='L182'></a><a href='#L182'>182</a>
248
+ <a name='L183'></a><a href='#L183'>183</a>
249
+ <a name='L184'></a><a href='#L184'>184</a>
250
+ <a name='L185'></a><a href='#L185'>185</a>
251
+ <a name='L186'></a><a href='#L186'>186</a>
252
+ <a name='L187'></a><a href='#L187'>187</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
205
253
  <span class="cline-any cline-yes">1x</span>
206
254
  <span class="cline-any cline-yes">1x</span>
207
255
  <span class="cline-any cline-yes">1x</span>
@@ -223,6 +271,44 @@
223
271
  <span class="cline-any cline-yes">1x</span>
224
272
  <span class="cline-any cline-yes">1x</span>
225
273
  <span class="cline-any cline-yes">1x</span>
274
+ <span class="cline-any cline-yes">1x</span>
275
+ <span class="cline-any cline-yes">1x</span>
276
+ <span class="cline-any cline-no">&nbsp;</span>
277
+ <span class="cline-any cline-no">&nbsp;</span>
278
+ <span class="cline-any cline-no">&nbsp;</span>
279
+ <span class="cline-any cline-no">&nbsp;</span>
280
+ <span class="cline-any cline-no">&nbsp;</span>
281
+ <span class="cline-any cline-no">&nbsp;</span>
282
+ <span class="cline-any cline-no">&nbsp;</span>
283
+ <span class="cline-any cline-no">&nbsp;</span>
284
+ <span class="cline-any cline-no">&nbsp;</span>
285
+ <span class="cline-any cline-no">&nbsp;</span>
286
+ <span class="cline-any cline-no">&nbsp;</span>
287
+ <span class="cline-any cline-no">&nbsp;</span>
288
+ <span class="cline-any cline-no">&nbsp;</span>
289
+ <span class="cline-any cline-no">&nbsp;</span>
290
+ <span class="cline-any cline-no">&nbsp;</span>
291
+ <span class="cline-any cline-yes">1x</span>
292
+ <span class="cline-any cline-yes">1x</span>
293
+ <span class="cline-any cline-yes">1x</span>
294
+ <span class="cline-any cline-yes">1x</span>
295
+ <span class="cline-any cline-yes">1x</span>
296
+ <span class="cline-any cline-yes">1x</span>
297
+ <span class="cline-any cline-yes">1x</span>
298
+ <span class="cline-any cline-yes">1x</span>
299
+ <span class="cline-any cline-yes">1x</span>
300
+ <span class="cline-any cline-yes">1x</span>
301
+ <span class="cline-any cline-yes">1x</span>
302
+ <span class="cline-any cline-yes">1x</span>
303
+ <span class="cline-any cline-yes">1x</span>
304
+ <span class="cline-any cline-yes">1x</span>
305
+ <span class="cline-any cline-yes">1x</span>
306
+ <span class="cline-any cline-yes">1x</span>
307
+ <span class="cline-any cline-yes">1x</span>
308
+ <span class="cline-any cline-yes">1x</span>
309
+ <span class="cline-any cline-yes">100x</span>
310
+ <span class="cline-any cline-yes">100x</span>
311
+ <span class="cline-any cline-yes">100x</span>
226
312
  <span class="cline-any cline-yes">100x</span>
227
313
  <span class="cline-any cline-yes">100x</span>
228
314
  <span class="cline-any cline-yes">100x</span>
@@ -231,14 +317,24 @@
231
317
  <span class="cline-any cline-yes">31x</span>
232
318
  <span class="cline-any cline-yes">31x</span>
233
319
  <span class="cline-any cline-yes">31x</span>
234
- <span class="cline-any cline-yes">74x</span>
320
+ <span class="cline-any cline-yes">100x</span>
235
321
  <span class="cline-any cline-yes">8x</span>
236
322
  <span class="cline-any cline-yes">8x</span>
237
323
  <span class="cline-any cline-yes">8x</span>
238
- <span class="cline-any cline-yes">63x</span>
239
- <span class="cline-any cline-yes">5x</span>
240
- <span class="cline-any cline-yes">5x</span>
241
- <span class="cline-any cline-yes">5x</span>
324
+ <span class="cline-any cline-yes">100x</span>
325
+ <span class="cline-any cline-yes">100x</span>
326
+ <span class="cline-any cline-yes">95x</span>
327
+ <span class="cline-any cline-yes">95x</span>
328
+ <span class="cline-any cline-yes">100x</span>
329
+ <span class="cline-any cline-no">&nbsp;</span>
330
+ <span class="cline-any cline-no">&nbsp;</span>
331
+ <span class="cline-any cline-no">&nbsp;</span>
332
+ <span class="cline-any cline-no">&nbsp;</span>
333
+ <span class="cline-any cline-no">&nbsp;</span>
334
+ <span class="cline-any cline-no">&nbsp;</span>
335
+ <span class="cline-any cline-yes">95x</span>
336
+ <span class="cline-any cline-yes">95x</span>
337
+ <span class="cline-any cline-yes">95x</span>
242
338
  <span class="cline-any cline-yes">1x</span>
243
339
  <span class="cline-any cline-yes">1x</span>
244
340
  <span class="cline-any cline-yes">1x</span>
@@ -346,11 +442,41 @@
346
442
  addWeeks,
347
443
  addMonths,
348
444
  startOfWeek,
445
+ setHours,
446
+ setMinutes,
349
447
  } from 'date-fns';
350
448
  import { PATTERNS } from '../parser/patterns.js';
351
449
  &nbsp;
352
450
  /**
353
- * Parse an absolute date string in various formats
451
+ * Parse a time string in HH:MM or H:MM format
452
+ *
453
+ * @param timeStr - Time string to parse (e.g., "17:00", "9:00")
454
+ * @returns Object with hours and minutes, or null if invalid
455
+ *
456
+ * @example
457
+ * parseTime("17:00") // =&gt; { hours: 17, minutes: 0 }
458
+ * parseTime("9:30") // =&gt; { hours: 9, minutes: 30 }
459
+ * parseTime("25:00") // =&gt; null (invalid hour)
460
+ */
461
+ export <span class="fstat-no" title="function not covered" >function parseTime(</span>
462
+ <span class="cstat-no" title="statement not covered" > timeStr: string,</span>
463
+ <span class="cstat-no" title="statement not covered" >): { hours: number; minutes: number } | null {</span>
464
+ <span class="cstat-no" title="statement not covered" > const match = timeStr.match(/^(\d{1,2}):(\d{2})$/);</span>
465
+ <span class="cstat-no" title="statement not covered" > if (!match || !match[1] || !match[2]) return null;</span>
466
+ <span class="cstat-no" title="statement not covered" ></span>
467
+ <span class="cstat-no" title="statement not covered" > const hours = parseInt(match[1], 10);</span>
468
+ <span class="cstat-no" title="statement not covered" > const minutes = parseInt(match[2], 10);</span>
469
+ <span class="cstat-no" title="statement not covered" ></span>
470
+ <span class="cstat-no" title="statement not covered" > // Validate ranges</span>
471
+ <span class="cstat-no" title="statement not covered" > if (hours &lt; 0 || hours &gt; 23 || minutes &lt; 0 || minutes &gt; 59) {</span>
472
+ <span class="cstat-no" title="statement not covered" > return null;</span>
473
+ <span class="cstat-no" title="statement not covered" > }</span>
474
+ <span class="cstat-no" title="statement not covered" ></span>
475
+ <span class="cstat-no" title="statement not covered" > return { hours, minutes };</span>
476
+ <span class="cstat-no" title="statement not covered" >}</span>
477
+ &nbsp;
478
+ /**
479
+ * Parse an absolute date string in various formats, with optional time
354
480
  *
355
481
  * Supported formats:
356
482
  * - ISO: 2026-01-25
@@ -358,24 +484,42 @@ import { PATTERNS } from '../parser/patterns.js';
358
484
  * - US full: 1/25/2026
359
485
  *
360
486
  * @param dateStr - Date string to parse
487
+ * @param timeStr - Optional time string in HH:MM or H:MM format
361
488
  * @returns Parsed Date object or null if invalid
489
+ *
490
+ * @example
491
+ * parseAbsoluteDate("2026-01-25") // =&gt; Date at midnight
492
+ * parseAbsoluteDate("2026-01-25", "17:00") // =&gt; Date at 5 PM
362
493
  */
363
- export function parseAbsoluteDate(dateStr: string): Date | null {
494
+ export function parseAbsoluteDate(
495
+ dateStr: string,
496
+ timeStr?: string,
497
+ ): Date | null {
364
498
  const referenceDate = new Date();
365
499
  &nbsp;
366
500
  // Try ISO format: 2026-01-25
367
501
  let date = parse(dateStr, 'yyyy-MM-dd', referenceDate);
368
- if (isValid(date)) return date;
502
+ if (!isValid(date)) {
503
+ // Try US short format with 2-digit year: 1/25/26
504
+ date = parse(dateStr, 'M/d/yy', referenceDate);
505
+ }
506
+ if (!isValid(date)) {
507
+ // Try US full format: 1/25/2026
508
+ date = parse(dateStr, 'M/d/yyyy', referenceDate);
509
+ }
369
510
  &nbsp;
370
- // Try US short format with 2-digit year: 1/25/26
371
- date = parse(dateStr, 'M/d/yy', referenceDate);
372
- if (isValid(date)) return date;
511
+ if (!isValid(date)) return null;
373
512
  &nbsp;
374
- // Try US full format: 1/25/2026
375
- date = parse(dateStr, 'M/d/yyyy', referenceDate);
376
- if (isValid(date)) return date;
513
+ // Apply time if provided
514
+ if (timeStr) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
515
+ <span class="cstat-no" title="statement not covered" > const time = parseTime(timeStr);</span>
516
+ <span class="cstat-no" title="statement not covered" > if (time) {</span>
517
+ <span class="cstat-no" title="statement not covered" > date = setHours(date, time.hours);</span>
518
+ <span class="cstat-no" title="statement not covered" > date = setMinutes(date, time.minutes);</span>
519
+ <span class="cstat-no" title="statement not covered" > }</span>
520
+ <span class="cstat-no" title="statement not covered" > }</span>
377
521
  &nbsp;
378
- return null;
522
+ return date;
379
523
  }
380
524
  &nbsp;
381
525
  /**
@@ -484,7 +628,7 @@ export function extractDateFromHeading(line: string): Date | null {
484
628
  <div class='footer quiet pad2 space-top1 center small'>
485
629
  Code coverage generated by
486
630
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
487
- at 2026-01-26T03:50:53.066Z
631
+ at 2026-02-05T05:58:13.697Z
488
632
  </div>
489
633
  <script src="../../prettify.js"></script>
490
634
  <script>
@@ -154,7 +154,7 @@ export function generateTaskId(
154
154
  <div class='footer quiet pad2 space-top1 center small'>
155
155
  Code coverage generated by
156
156
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
157
- at 2026-01-26T03:50:53.066Z
157
+ at 2026-02-05T05:58:13.697Z
158
158
  </div>
159
159
  <script src="../../prettify.js"></script>
160
160
  <script>
@@ -23,30 +23,30 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">100% </span>
26
+ <span class="strong">90.18% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>166/166</span>
28
+ <span class='fraction'>193/214</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">100% </span>
33
+ <span class="strong">96.15% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>28/28</span>
35
+ <span class='fraction'>25/26</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">100% </span>
40
+ <span class="strong">80% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>4/4</span>
42
+ <span class='fraction'>4/5</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">100% </span>
47
+ <span class="strong">90.18% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>166/166</span>
49
+ <span class='fraction'>193/214</span>
50
50
  </div>
51
51
 
52
52
 
@@ -80,17 +80,17 @@
80
80
  </thead>
81
81
  <tbody><tr>
82
82
  <td class="file high" data-value="dates.ts"><a href="dates.ts.html">dates.ts</a></td>
83
- <td data-value="100" class="pic high">
84
- <div class="chart"><div class="cover-fill cover-full" style="width: 100%"></div><div class="cover-empty" style="width: 0%"></div></div>
83
+ <td data-value="88.7" class="pic high">
84
+ <div class="chart"><div class="cover-fill" style="width: 88%"></div><div class="cover-empty" style="width: 12%"></div></div>
85
85
  </td>
86
- <td data-value="100" class="pct high">100%</td>
87
- <td data-value="138" class="abs high">138/138</td>
88
- <td data-value="100" class="pct high">100%</td>
89
- <td data-value="27" class="abs high">27/27</td>
90
- <td data-value="100" class="pct high">100%</td>
91
- <td data-value="3" class="abs high">3/3</td>
92
- <td data-value="100" class="pct high">100%</td>
93
- <td data-value="138" class="abs high">138/138</td>
86
+ <td data-value="88.7" class="pct high">88.7%</td>
87
+ <td data-value="186" class="abs high">165/186</td>
88
+ <td data-value="96" class="pct high">96%</td>
89
+ <td data-value="25" class="abs high">24/25</td>
90
+ <td data-value="75" class="pct medium">75%</td>
91
+ <td data-value="4" class="abs medium">3/4</td>
92
+ <td data-value="88.7" class="pct high">88.7%</td>
93
+ <td data-value="186" class="abs high">165/186</td>
94
94
  </tr>
95
95
 
96
96
  <tr>
@@ -116,7 +116,7 @@
116
116
  <div class='footer quiet pad2 space-top1 center small'>
117
117
  Code coverage generated by
118
118
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
119
- at 2026-01-26T03:50:53.066Z
119
+ at 2026-02-05T05:58:13.697Z
120
120
  </div>
121
121
  <script src="../../prettify.js"></script>
122
122
  <script>