|
1 | 1 | import { describe, expect, test } from 'vitest' |
2 | | -import type { AnnotationTag, AnnotationComment } from '../src/core/types' |
| 2 | +import type { AnnotationComment } from '../src/core/types' |
3 | 3 | import { parseAnnotationTags } from '../src/parsers/annotation-tags' |
4 | 4 | import { parseParentComment } from '../src/parsers/parent-comment' |
5 | 5 | import { splitCodeLines } from './utils' |
6 | 6 |
|
7 | | -describe('parseParentComment', () => { |
8 | | - test('Returns undefined when no parent comment is found', () => { |
9 | | - expect( |
10 | | - getParentComment(` |
11 | | -// This comment is not on the same line as the tag |
12 | | -console.log('Some code containing [!ins] outside of a comment'); |
13 | | - `) |
14 | | - ).toEqual(undefined) |
| 7 | +describe('parseParentComment()', () => { |
| 8 | + describe('Returns undefined when no valid parent comment is found', () => { |
| 9 | + describe('Single-line comment syntax', () => { |
| 10 | + test('No comment syntax in the same line', () => { |
| 11 | + expect(getParentComment(`console.log('This is [!ins] in a string')`)).toEqual(undefined) |
| 12 | + }) |
| 13 | + test('Comment syntax located after the annotation tag', () => { |
| 14 | + expect(getParentComment(`console.log('More [!test] text') // Hi!`)).toEqual(undefined) |
| 15 | + }) |
| 16 | + test('Missing whitespace before comment opening syntax', () => { |
| 17 | + expect(getParentComment(`someCode()// [!note] Invalid syntax`)).toEqual(undefined) |
| 18 | + }) |
| 19 | + test('Missing whitespace before annotation tag', () => { |
| 20 | + expect(getParentComment(`someCode() //[!note] Invalid syntax`)).toEqual(undefined) |
| 21 | + }) |
| 22 | + test('Content between comment opening and annotation tag', () => { |
| 23 | + expect(getParentComment(`someCode() // Hi [!note] This won't work`)).toEqual(undefined) |
| 24 | + }) |
| 25 | + }) |
15 | 26 | }) |
16 | 27 |
|
17 | | - describe('Single-line comments', () => { |
| 28 | + describe('Supports single-line comments', () => { |
18 | 29 | describe('Starting at the beginning of the line', () => { |
19 | 30 | const syntaxes = [ |
20 | 31 | // Starting at column 0, followed by a space |
@@ -146,6 +157,94 @@ console.log('Some code containing [!ins] outside of a comment'); |
146 | 157 | expect(comment.contentRanges).toEqual([{ start: { line: 2, column: commentLine.indexOf('Mismatching') }, end: { line: 2 } }]) |
147 | 158 | }) |
148 | 159 | }) |
| 160 | + describe(`Allows multi-line content by repeating the same opening syntax`, () => { |
| 161 | + test('Single annotation comment with multi-line content', () => { |
| 162 | + const lines = [ |
| 163 | + // Starts like a regular single-line annotation comment... |
| 164 | + '// [!note] Annotation content', |
| 165 | + // ...but continues on the next lines by repeating the comment opening syntax |
| 166 | + '// that spans multiple lines', |
| 167 | + '// until the comment ends', |
| 168 | + // ...and ends when the comment syntax is not repeated |
| 169 | + 'someCode()', |
| 170 | + ] |
| 171 | + const comment = getParentComment(getTestCode(lines.join('\n'))) as AnnotationComment |
| 172 | + expect(comment.contents).toEqual(['Annotation content', 'that spans multiple lines', 'until the comment ends']) |
| 173 | + expect(comment.commentRange).toEqual({ start: { line: 2 }, end: { line: 4 } }) |
| 174 | + expect(comment.contentRanges).toEqual([ |
| 175 | + { start: { line: 2, column: lines[0].indexOf('Annotation') }, end: { line: 2 } }, |
| 176 | + { start: { line: 3, column: lines[1].indexOf('that') }, end: { line: 3 } }, |
| 177 | + { start: { line: 4, column: lines[2].indexOf('until') }, end: { line: 4 } }, |
| 178 | + ]) |
| 179 | + }) |
| 180 | + test('Multi-line content ends when encountering a different comment syntax', () => { |
| 181 | + const lines = [ |
| 182 | + // Starts like a regular single-line annotation comment... |
| 183 | + '// [!note] Annotation content', |
| 184 | + // ...but continues on the next line by repeating the comment opening syntax |
| 185 | + '// that spans multiple lines', |
| 186 | + // ...and ends when encountering a different comment syntax |
| 187 | + '# This is a regular comment and not part of the annotation', |
| 188 | + ] |
| 189 | + const comment = getParentComment(getTestCode(lines.join('\n'))) as AnnotationComment |
| 190 | + expect(comment.contents).toEqual(['Annotation content', 'that spans multiple lines']) |
| 191 | + expect(comment.commentRange).toEqual({ start: { line: 2 }, end: { line: 3 } }) |
| 192 | + expect(comment.contentRanges).toEqual([ |
| 193 | + { start: { line: 2, column: lines[0].indexOf('Annotation') }, end: { line: 2 } }, |
| 194 | + { start: { line: 3, column: lines[1].indexOf('that') }, end: { line: 3 } }, |
| 195 | + ]) |
| 196 | + }) |
| 197 | + test('Multi-line content ends when encountering another annotation comment', () => { |
| 198 | + const lines = [ |
| 199 | + // Starts like a regular single-line annotation comment... |
| 200 | + '// [!note] Annotation 1 content', |
| 201 | + // ...but continues on the next line by repeating the comment opening syntax |
| 202 | + '// that spans multiple lines', |
| 203 | + // ...and ends when encountering another annotation comment |
| 204 | + '// [!test] Annotation 2 content', |
| 205 | + ] |
| 206 | + const comment = getParentComment(getTestCode(lines.join('\n'))) as AnnotationComment |
| 207 | + expect(comment.contents).toEqual(['Annotation 1 content', 'that spans multiple lines']) |
| 208 | + expect(comment.commentRange).toEqual({ start: { line: 2 }, end: { line: 3 } }) |
| 209 | + expect(comment.contentRanges).toEqual([ |
| 210 | + { start: { line: 2, column: lines[0].indexOf('Annotation') }, end: { line: 2 } }, |
| 211 | + { start: { line: 3, column: lines[1].indexOf('that') }, end: { line: 3 } }, |
| 212 | + ]) |
| 213 | + }) |
| 214 | + test('Multi-line content ends when encountering "---" on its own line', () => { |
| 215 | + const lines = [ |
| 216 | + // Starts like a regular single-line annotation comment... |
| 217 | + '// [!note] Annotation content', |
| 218 | + // ...but continues on the next line by repeating the comment opening syntax |
| 219 | + '// that spans multiple lines', |
| 220 | + // ...and ends when encountering "---" on its own line |
| 221 | + '// ---', |
| 222 | + '// This is a regular comment and not part of the annotation', |
| 223 | + ] |
| 224 | + const comment = getParentComment(getTestCode(lines.join('\n'))) as AnnotationComment |
| 225 | + expect(comment.contents).toEqual(['Annotation content', 'that spans multiple lines']) |
| 226 | + // Expect the "---" line to be included in the comment range |
| 227 | + // so it will be removed when the comment is removed |
| 228 | + expect(comment.commentRange).toEqual({ start: { line: 2 }, end: { line: 4 } }) |
| 229 | + // However, it must not be included in the content ranges |
| 230 | + expect(comment.contentRanges).toEqual([ |
| 231 | + { start: { line: 2, column: lines[0].indexOf('Annotation') }, end: { line: 2 } }, |
| 232 | + { start: { line: 3, column: lines[1].indexOf('that') }, end: { line: 3 } }, |
| 233 | + ]) |
| 234 | + }) |
| 235 | + test('Comments starting after code on the same line cannot be multi-line', () => { |
| 236 | + const lines = [ |
| 237 | + // A regular single-line comment that starts after some code |
| 238 | + 'someCode() // [!note] Annotation content', |
| 239 | + // ...cannot be continued on the next line |
| 240 | + '// This is a regular comment and not part of the annotation', |
| 241 | + ] |
| 242 | + const comment = getParentComment(getTestCode(lines.join('\n'))) as AnnotationComment |
| 243 | + expect(comment.contents).toEqual(['Annotation content']) |
| 244 | + expect(comment.commentRange).toEqual({ start: { line: 2, column: lines[0].indexOf(' // [!') }, end: { line: 2 } }) |
| 245 | + expect(comment.contentRanges).toEqual([{ start: { line: 2, column: lines[0].indexOf('Annotation') }, end: { line: 2 } }]) |
| 246 | + }) |
| 247 | + }) |
149 | 248 | }) |
150 | 249 |
|
151 | 250 | function getTestCode(commentLine: string) { |
|
0 commit comments