(line: string)
| 104 | } |
| 105 | |
| 106 | export const parseAtInLine = (line: string): MentionParseResult => { |
| 107 | const atIndex = line.lastIndexOf('@') |
| 108 | if (atIndex === -1) { |
| 109 | return { active: false, query: '', atIndex: -1 } |
| 110 | } |
| 111 | |
| 112 | // Check if @ is inside string delimiters |
| 113 | if (isInsideStringDelimiters(line, atIndex)) { |
| 114 | return { active: false, query: '', atIndex: -1 } |
| 115 | } |
| 116 | |
| 117 | const beforeChar = atIndex > 0 ? line[atIndex - 1] : '' |
| 118 | |
| 119 | // Don't trigger on escaped @: \@ |
| 120 | if (beforeChar === '\\') { |
| 121 | return { active: false, query: '', atIndex: -1 } |
| 122 | } |
| 123 | |
| 124 | // Don't trigger on email-like patterns or URLs: user@example.com, https://example.com/@user |
| 125 | // Check for alphanumeric, dot, or colon before @ |
| 126 | if (beforeChar && /[a-zA-Z0-9.:]/.test(beforeChar)) { |
| 127 | return { active: false, query: '', atIndex: -1 } |
| 128 | } |
| 129 | |
| 130 | // Require whitespace or start of line before @ |
| 131 | if (beforeChar && !/\s/.test(beforeChar)) { |
| 132 | return { active: false, query: '', atIndex: -1 } |
| 133 | } |
| 134 | |
| 135 | const afterAt = line.slice(atIndex + 1) |
| 136 | const firstSpaceIndex = afterAt.search(/\s/) |
| 137 | const query = firstSpaceIndex === -1 ? afterAt : afterAt.slice(0, firstSpaceIndex) |
| 138 | |
| 139 | if (firstSpaceIndex !== -1) { |
| 140 | return { active: false, query: '', atIndex: -1 } |
| 141 | } |
| 142 | |
| 143 | return { active: true, query, atIndex } |
| 144 | } |
| 145 | |
| 146 | const parseMentionContext = ( |
| 147 | input: string, |
no test coverage detected