-
Notifications
You must be signed in to change notification settings - Fork 66.9k
Expand file tree
/
Copy pathcode-annotation-comment-spacing.ts
More file actions
103 lines (91 loc) · 3.75 KB
/
code-annotation-comment-spacing.ts
File metadata and controls
103 lines (91 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import { addError, filterTokens } from 'markdownlint-rule-helpers'
import type { RuleParams, RuleErrorCallback, MarkdownToken } from '@/content-linter/types'
export const codeAnnotationCommentSpacing = {
names: ['GHD045', 'code-annotation-comment-spacing'],
description:
'Code comments in annotation blocks must have exactly one space after the comment character(s)',
tags: ['code', 'comments', 'annotate', 'spacing'],
parser: 'markdownit' as const,
function: (params: RuleParams, onError: RuleErrorCallback) => {
filterTokens(params, 'fence', (token: MarkdownToken) => {
if (!token.info?.includes('annotate')) return
const content = token.content
if (!content) return
const lines = content.split('\n')
lines.forEach((line: string, index: number) => {
const trimmedLine = line.trim()
if (!trimmedLine) return
// Define a map of comment patterns
const commentPatterns: Record<string, RegExp> = {
'//': /^(\/\/)(.*)/, // JavaScript/TypeScript/Java/C# style comments
'#': /^(#)(.*)/, // Python/Ruby/Shell/YAML style comments
'--': /^(--)(.*)/, // SQL/Lua style comments
}
// Check for different comment patterns
let commentMatch: RegExpMatchArray | null = null
let commentChar: string | null = null
let restOfLine: string | null = null
// Iterate over the map to find a matching comment style
for (const [char, pattern] of Object.entries(commentPatterns)) {
if (trimmedLine.startsWith(char)) {
commentMatch = trimmedLine.match(pattern)
commentChar = char
restOfLine = commentMatch ? commentMatch[2] : ''
break
}
}
if (commentMatch && restOfLine !== null && commentChar !== null) {
// Skip shebang lines (#!/...)
if (trimmedLine.startsWith('#!')) {
return
}
// Allow empty comments or comments with exactly one space
if (restOfLine === '' || restOfLine.startsWith(' ')) {
// If it starts with a space, make sure it's exactly one space
if (restOfLine.startsWith(' ') && restOfLine.length > 1 && restOfLine[1] === ' ') {
// Multiple spaces - this is an error
const lineNumber: number = token.lineNumber + index + 1
const fixedLine: string = line.replace(
new RegExp(`^(\\s*${commentChar.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})\\s+`),
`$1 `,
)
addError(
onError,
lineNumber,
`Comment must have exactly one space after '${commentChar}', found multiple spaces`,
line,
[1, line.length],
{
lineNumber,
editColumn: 1,
deleteCount: line.length,
insertText: fixedLine,
},
)
}
// Single space or empty - this is correct
return
} else {
// No space after comment character - this is an error
const lineNumber: number = token.lineNumber + index + 1
const leadingWhitespace: string = line.match(/^\s*/)![0]
const fixedLine: string = `${leadingWhitespace + commentChar} ${restOfLine}`
addError(
onError,
lineNumber,
`Comment must have exactly one space after '${commentChar}'`,
line,
[1, line.length],
{
lineNumber,
editColumn: 1,
deleteCount: line.length,
insertText: fixedLine,
},
)
}
}
})
})
},
}