Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/services/NoteCreator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,24 @@ describe('NoteCreator.deriveTitle', () => {
expect(NoteCreator.deriveTitle('Meeting: Q1 "plan" #person', '#person'))
.toBe('Meeting Q1 plan');
});

it('strips extra leading separator after task checkbox (iterative marker stripping)', () => {
// "- [ ] - content" — after stripping "- " and "[ ] ", another "- " remains
expect(NoteCreator.deriveTitle('- [ ] - some content #idea', '#idea'))
.toBe('some content');
});

it('strips timestamp prefix from title in task line with timestamp', () => {
// "- [ ] - 12:30 - content" — the timestamp should not appear in the entity name
expect(NoteCreator.deriveTitle('- [ ] - 12:30 - some content #idea', '#idea'))
.toBe('some content');
});

it('strips timestamp prefix when line has wikilink after timestamp', () => {
// "- [ ] - 12:30 - [[some text]] #idea" — entity name from wikilink text only
expect(NoteCreator.deriveTitle('- [ ] - 12:30 - [[some text]] #idea', '#idea'))
.toBe('some text');
});
});

// ---------------------------------------------------------------------------
Expand Down
31 changes: 23 additions & 8 deletions src/services/NoteCreator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,20 @@ export class NoteCreator {
// Unwrap wikilinks: [[Alice]] → Alice, [[Alice|Alias]] → Alice
s = s.replace(/\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/g, '$1').trim();

// Strip leading list / task markers (same order as PatternMatcher)
s = s.replace(/^\d+[.)]\s*/, '').trim(); // "1. " / "1)"
s = s.replace(/^[-*+]\s*/, '').trim(); // "- " / "* " / "+ "
s = s.replace(/^\[[ xX]\]\s*/, '').trim(); // "[ ] " / "[x] "
// Strip leading list / task markers iteratively to handle nested formats
// such as "- [ ] - content" where a separator "- " follows the task marker.
let prev: string;
do {
prev = s;
s = s.replace(/^\d+[.)]\s*/, '').trim(); // "1. " / "1)"
s = s.replace(/^[-*+]\s*/, '').trim(); // "- " / "* " / "+ "
s = s.replace(/^\[[ xX]\]\s*/, '').trim(); // "[ ] " / "[x] "
} while (s !== prev);

// Strip a leading timestamp (e.g. "12:30" or "9:45") that may appear as a
// time annotation between list markers and the actual content, optionally
// followed by a separator dash ("12:30 - content" → "content").
s = s.replace(/^\d{1,2}:\d{2}\s*[-–]?\s*/, '').trim();

s = s.replace(/\s+/g, ' ').trim();

Expand All @@ -103,10 +113,15 @@ export class NoteCreator {
const re = NoteCreator.tagRegex(triggerTag);
let s = lineText.replace(re, '$1').trim();

// Strip leading list / task markers (same order as PatternMatcher)
s = s.replace(/^\d+[.)]\s*/, '').trim(); // "1. " / "1)"
s = s.replace(/^[-*+]\s*/, '').trim(); // "- " / "* " / "+ "
s = s.replace(/^\[[ xX]\]\s*/, '').trim(); // "[ ] " / "[x] "
// Strip leading list / task markers iteratively to handle nested formats
// such as "- [ ] - content" where a separator "- " follows the task marker.
let prev: string;
do {
prev = s;
s = s.replace(/^\d+[.)]\s*/, '').trim(); // "1. " / "1)"
s = s.replace(/^[-*+]\s*/, '').trim(); // "- " / "* " / "+ "
s = s.replace(/^\[[ xX]\]\s*/, '').trim(); // "[ ] " / "[x] "
} while (s !== prev);

return s.replace(/\s+/g, ' ').trim();
}
Expand Down
12 changes: 12 additions & 0 deletions src/services/PatternMatcher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,18 @@ describe('PatternMatcher.match — Case 2 (full-line)', () => {
it('line with plain text plus an embedded wikilink matches as full-line', () => {
expect(pm.match('Met [[Sarah]] #person', [PERSON], CLEAR, allResolved)).toEqual(fullLine(PERSON));
});

it('resolved wikilink with only a timestamp prefix returns null — timestamp is not meaningful content', () => {
// "- [ ] - 12:30 - [[some text]] #idea" where the link is resolved:
// the only surrounding content is a timestamp, which is not a useful entity title
expect(pm.match('- [ ] - 12:30 - [[some text]] #idea', [IDEA], CLEAR, allResolved)).toBeNull();
});

it('unresolved wikilink after timestamp in task item is detected as Case 1', () => {
// Even with a timestamp prefix, an unresolved wikilink must trigger Case 1
expect(pm.match('- [ ] - 12:30 - [[some text]] #idea', [IDEA], CLEAR, noneResolved))
.toEqual(unresolvedLink(IDEA, 'some text'));
});
});

// --- disabled ---
Expand Down
18 changes: 15 additions & 3 deletions src/services/PatternMatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,21 @@ export class PatternMatcher {
private hasMeaningfulContent(line: string, tag: string): boolean {
let s = line.replace(this.tagRegex(tag), '$1').trim();
s = s.replace(/\[\[[^\]]*\]\]/g, '').trim(); // strip wikilinks
s = s.replace(/^\d+[.)]\s*/, '').trim(); // ordered list: "1. " or "1)"
s = s.replace(/^[-*+]\s*/, '').trim(); // unordered list: "- ", "* ", "+ "
s = s.replace(/^\[[ xX]\]\s*/, '').trim(); // task checkbox: "[ ] " or "[x] "

// Strip leading list / task markers iteratively to handle nested formats
// such as "- [ ] - content" where a separator "- " follows the task marker.
let prev: string;
do {
prev = s;
s = s.replace(/^\d+[.)]\s*/, '').trim(); // ordered list: "1. " or "1)"
s = s.replace(/^[-*+]\s*/, '').trim(); // unordered list: "- ", "* ", "+ "
s = s.replace(/^\[[ xX]\]\s*/, '').trim(); // task checkbox: "[ ] " or "[x] "
} while (s !== prev);

// A leading timestamp (e.g. "12:30") used as a time annotation between markers
// and content is not considered meaningful for deriving an entity title.
s = s.replace(/^\d{1,2}:\d{2}\s*[-–]?\s*/, '').trim();

return s.length > 0;
}

Expand Down
Loading