Skip to content

Commit 29fbf9b

Browse files
committed
Add ignore-tags logic, tests
1 parent 08fda18 commit 29fbf9b

3 files changed

Lines changed: 159 additions & 7 deletions

File tree

packages/annotation-comments/src/core/parse.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,44 @@ export function parseAnnotationComments(options: ParseAnnotationCommentsOptions)
1414
// Find annotation tags in the code
1515
const annotationTags = parseAnnotationTags({ codeLines })
1616

17+
const ignoreCountPerTagName = new Map<string, number>()
18+
let tagsIgnoredUntilLineIndex = -1
19+
1720
let previousCommentRanges: SourceRange[] = []
1821
annotationTags.forEach((tag) => {
1922
// Ignore the current tag if it is located inside the content ranges
2023
// of the previously processed annotation comment
2124
if (previousCommentRanges.some((range) => secondRangeIsInFirst(range, tag.range))) return
2225

23-
// TODO: Handle `[!ignore-tags]` logic
24-
2526
// Attempt to find a comment that the current annotation tag is located in
2627
const comment = parseParentComment({ codeLines, tag })
2728
if (!comment) return
2829

29-
// If a comment was found, add the tag and comment to the list of annotation comments
30+
// Handle ignored tags based on lines
31+
if (tagsIgnoredUntilLineIndex >= tag.range.start.line) return
32+
// Handle ignored tags based on tag names
33+
const ignoreCount = ignoreCountPerTagName.get(tag.name) ?? 0
34+
if (ignoreCount > 0) {
35+
ignoreCountPerTagName.set(tag.name, ignoreCount - 1)
36+
return
37+
}
38+
// Allow creating new ignores
39+
if (tag.name === 'ignore-tags') {
40+
// By definition, `ignore-tags` must be on its own line
41+
if (comment.commentRange.start.column || comment.commentRange.end.column) return
42+
const ignoreRange = tag.relativeTargetRange ?? 1
43+
if (typeof tag.targetSearchQuery === 'string') {
44+
const targetTagNames = tag.targetSearchQuery.split(',').map((name) => name.trim())
45+
targetTagNames.forEach((name) => {
46+
ignoreCountPerTagName.set(name, ignoreRange)
47+
})
48+
} else if (ignoreRange > 0) {
49+
tagsIgnoredUntilLineIndex = tag.range.end.line + ignoreRange
50+
}
51+
return
52+
}
53+
54+
// If we arrive here, add the tag and comment to the list of annotation comments
3055
annotationComments.push(comment)
3156
previousCommentRanges = comment.contentRanges
3257
})

packages/annotation-comments/src/parsers/comment-types/single-line.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,16 @@ export function parseSingleLineParentComment(options: ParseParentCommentOptions)
8383
comment.contents.push(tagLineContent.content)
8484
comment.contentRanges.push(tagLineContent.contentRange)
8585
}
86-
// If there was only whitespace before the beginning of the comment,
87-
// and no chaining was detected, try to expand the comment end location
86+
// For supported annotation comments, allow expanding the comment end location
8887
// and annotation content to subsequent comment lines
89-
if (tagLine.slice(0, singleLineCommentSyntax.startColumn).trim() === '' && !chainedSingleLineCommentSyntax) {
88+
const allowMultiLineExpansion =
89+
// To allow expansion, the initial comment must start on its own line
90+
tagLine.slice(0, singleLineCommentSyntax.startColumn).trim() === '' &&
91+
// Chaining is not allowed
92+
!chainedSingleLineCommentSyntax &&
93+
// It doesn't make sense to expand annotation comments that don't support content
94+
tag.name !== 'ignore-tags'
95+
if (allowMultiLineExpansion) {
9096
for (let lineIndex = tagLineIndex + 1; lineIndex < codeLines.length; lineIndex++) {
9197
const line = codeLines[lineIndex]
9298
const commentStart = line.search(/\S/)

packages/annotation-comments/test/parse.test.ts

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,128 @@ countdown(5)
232232
] as PartialAnnotationComment[])
233233
})
234234

235-
// TODO: We also need to implement and test the `[!ignore-tags]` logic
235+
describe('Supports ignoring unwanted annotations', () => {
236+
test('[!ignore-tags] ignores all annotations on the next line', () => {
237+
const lines = [
238+
`// [!before] This is before any ignores`,
239+
`console.log('Some code')`,
240+
`// [!ignore-tags]`,
241+
`testCode() // [!ignored] This should not be parsed`,
242+
`// [!after] This should be parsed again`,
243+
]
244+
const comments = getComments(lines.join('\n'))
245+
expect(comments).toHaveLength(2)
246+
expect(comments).toMatchObject([
247+
{
248+
tag: { name: 'before', targetSearchQuery: undefined },
249+
contents: [`This is before any ignores`],
250+
},
251+
{
252+
tag: { name: 'after', targetSearchQuery: undefined },
253+
contents: [`This should be parsed again`],
254+
},
255+
] as PartialAnnotationComment[])
256+
})
257+
test('[!ignore-tags:2] ignores the next two lines', () => {
258+
const lines = [
259+
`// [!before] This is before any ignores`,
260+
`console.log('Some code')`,
261+
`// [!ignore-tags:2]`,
262+
`testCode() // [!ignored] This should not be parsed`,
263+
`// [!ignored] Still ignored`,
264+
`// [!after] This should be parsed again`,
265+
]
266+
const comments = getComments(lines.join('\n'))
267+
expect(comments).toHaveLength(2)
268+
expect(comments).toMatchObject([
269+
{
270+
tag: { name: 'before', targetSearchQuery: undefined },
271+
contents: [`This is before any ignores`],
272+
},
273+
{
274+
tag: { name: 'after', targetSearchQuery: undefined },
275+
contents: [`This should be parsed again`],
276+
},
277+
] as PartialAnnotationComment[])
278+
})
279+
test('[!ignore-tags:note] ignores the next occurrence of "note"', () => {
280+
const lines = [
281+
`// [!before] This is before any ignores`,
282+
`// [!ignore-tags:note]`,
283+
`console.log('Some code')`,
284+
`testCode() // [!note] This should not be parsed`,
285+
`// [!note] This should be parsed again`,
286+
]
287+
const comments = getComments(lines.join('\n'))
288+
expect(comments).toHaveLength(2)
289+
expect(comments).toMatchObject([
290+
{
291+
tag: { name: 'before', targetSearchQuery: undefined },
292+
contents: [`This is before any ignores`],
293+
},
294+
{
295+
tag: { name: 'note', targetSearchQuery: undefined },
296+
contents: [`This should be parsed again`],
297+
},
298+
] as PartialAnnotationComment[])
299+
})
300+
test('[!ignore-tags:note,ins:3] ignores the next 3 occurrences of "note" and "ins"', () => {
301+
const lines = [
302+
`// [!before] This is before any ignores`,
303+
`// [!ignore-tags:note,ins:3]`,
304+
`console.log('Some code') // [!ins]`,
305+
`testCode() // [!note] This should not be parsed`,
306+
`// [!ins] // [!note] Still ignored`,
307+
`// [!ins] // [!note] Still ignored`,
308+
`console.log('Test') // [!ins]`,
309+
`// [!note] This should be parsed again`,
310+
]
311+
const comments = getComments(lines.join('\n'))
312+
expect(comments).toHaveLength(3)
313+
expect(comments).toMatchObject([
314+
{
315+
tag: { name: 'before', targetSearchQuery: undefined },
316+
contents: [`This is before any ignores`],
317+
},
318+
{
319+
tag: { name: 'ins', targetSearchQuery: undefined },
320+
contents: [],
321+
},
322+
{
323+
tag: { name: 'note', targetSearchQuery: undefined },
324+
contents: [`This should be parsed again`],
325+
},
326+
] as PartialAnnotationComment[])
327+
})
328+
test('Ignores work in multi-line comments', () => {
329+
const lines = [
330+
`/*`,
331+
` [!before] This is before any ignores`,
332+
` [!ignore-tags]`,
333+
` [!note] This should not be parsed`,
334+
` [!note] This should be parsed again`,
335+
`*/`,
336+
`console.log('Some code')`,
337+
`testCode() // [!ins]`,
338+
]
339+
const comments = getComments(lines.join('\n'))
340+
expect(comments).toHaveLength(3)
341+
expect(comments).toMatchObject([
342+
{
343+
tag: { name: 'before', targetSearchQuery: undefined },
344+
contents: [`This is before any ignores`],
345+
},
346+
{
347+
tag: { name: 'note', targetSearchQuery: undefined },
348+
contents: [`This should be parsed again`],
349+
},
350+
{
351+
tag: { name: 'ins', targetSearchQuery: undefined },
352+
contents: [],
353+
},
354+
] as PartialAnnotationComment[])
355+
})
356+
})
236357

237358
function getComments(code: string) {
238359
const codeLines = splitCodeLines(code)

0 commit comments

Comments
 (0)