Skip to content

Commit 0be59e7

Browse files
authored
fix: file-aware .hbs copyright parsing to avoid code corruption (#190)
- Remove generic ' ' prefix from commentPrefixes to prevent false positives - Add getCommentPrefixesForFile() for file-type-aware prefix detection - Track {{! ... }} comment block state for .hbs files - Only apply indented prefix detection inside {{! }} blocks - Prevents JavaScript code in <script> tags from being modified - Updates tests to pass inHbsCommentBlock parameter
1 parent 8df03b7 commit 0be59e7

2 files changed

Lines changed: 62 additions & 17 deletions

File tree

licensecheck/update.go

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,30 @@ func extractAllCopyrightInfo(filePath string) ([]*CopyrightInfo, error) {
3939
lineNum := 0
4040
var copyrights []*CopyrightInfo
4141

42+
// Track if we're inside a {{! ... }} comment block for .hbs files
43+
isHbsFile := strings.ToLower(filepath.Ext(filePath)) == ".hbs"
44+
inHbsCommentBlock := false
45+
4246
// Scan entire file for all copyright statements
4347
for scanner.Scan() {
4448
lineNum++
4549
line := scanner.Text()
4650

51+
// For .hbs files, track comment block state
52+
if isHbsFile {
53+
// Check for start of multi-line comment block: {{! at start (not closed on same line)
54+
if strings.Contains(line, "{{!") && !strings.Contains(line, "}}") {
55+
inHbsCommentBlock = true
56+
}
57+
// Check for end of comment block
58+
if inHbsCommentBlock && strings.Contains(line, "}}") {
59+
inHbsCommentBlock = false
60+
}
61+
}
62+
4763
// Check if line contains "copyright"
4864
if strings.Contains(strings.ToLower(line), "copyright") {
49-
info := parseCopyrightLine(line, lineNum, filePath)
65+
info := parseCopyrightLine(line, lineNum, filePath, inHbsCommentBlock)
5066
if info != nil {
5167
copyrights = append(copyrights, info)
5268
}
@@ -57,11 +73,15 @@ func extractAllCopyrightInfo(filePath string) ([]*CopyrightInfo, error) {
5773
}
5874

5975
// parseCopyrightLine extracts copyright details from a line
60-
func parseCopyrightLine(line string, lineNum int, filePath string) *CopyrightInfo {
61-
// 1. Determine the prefix and content source
76+
// parseCopyrightLine extracts copyright details from a line
77+
// inHbsCommentBlock indicates if we're inside a {{! ... }} block (for .hbs files)
78+
func parseCopyrightLine(line string, lineNum int, filePath string, inHbsCommentBlock bool) *CopyrightInfo {
79+
// 1. Determine the prefix and content source (file-aware)
80+
// Pass inHbsCommentBlock to only allow indented prefixes inside comment blocks
81+
prefixes := getCommentPrefixesForFile(filePath, inHbsCommentBlock)
6282
bestIdx := -1
6383
bestPrefix := ""
64-
for _, p := range commentPrefixes {
84+
for _, p := range prefixes {
6585
if idx := strings.Index(line, p); idx >= 0 {
6686
if bestIdx == -1 || idx < bestIdx {
6787
bestIdx = idx
@@ -251,10 +271,27 @@ var commentPrefixes = []string{
251271
"// ", "//",
252272
"# ", "#",
253273
"% ", "%",
254-
" ",
255274
"* ", "*",
256275
}
257276

277+
// hbsIndentedPrefixes are additional prefixes for .hbs files (multi-line {{! }} blocks)
278+
var hbsIndentedPrefixes = []string{
279+
" ", // Two spaces (common indentation inside {{! }} blocks)
280+
"\t", // Tab indentation
281+
}
282+
283+
// getCommentPrefixesForFile returns the appropriate comment prefixes for a file type
284+
// inHbsCommentBlock indicates if we're inside a {{! ... }} block in .hbs files
285+
func getCommentPrefixesForFile(filePath string, inHbsCommentBlock bool) []string {
286+
ext := strings.ToLower(filepath.Ext(filePath))
287+
if ext == ".hbs" && inHbsCommentBlock {
288+
// Only apply indented prefixes when inside a {{! ... }} comment block
289+
// This prevents matching JavaScript code elsewhere in the file
290+
return append(commentPrefixes, hbsIndentedPrefixes...)
291+
}
292+
return commentPrefixes
293+
}
294+
258295
// hasSpecialFirstLine checks if the file content starts with a special line
259296
// that should be preserved (like shebangs, XML declarations, etc.)
260297
func hasSpecialFirstLine(content []byte, filePath string) bool {

licensecheck/update_test.go

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ import (
1717

1818
func TestParseCopyrightLine(t *testing.T) {
1919
tests := []struct {
20-
name string
21-
line string
22-
lineNum int
23-
expectedInfo *CopyrightInfo
24-
expectNil bool
20+
name string
21+
line string
22+
lineNum int
23+
filePath string // optional, defaults to "file.go"
24+
inHbsCommentBlock bool // true if inside {{! ... }} block
25+
expectedInfo *CopyrightInfo
26+
expectNil bool
2527
}{
2628
{
2729
name: "Simple copyright with single year",
@@ -100,9 +102,11 @@ func TestParseCopyrightLine(t *testing.T) {
100102
},
101103
},
102104
{
103-
name: "Handlebars indented copyright",
104-
line: " Copyright IBM Corp. 2021, 2025",
105-
lineNum: 2,
105+
name: "Handlebars indented copyright",
106+
line: " Copyright IBM Corp. 2021, 2025",
107+
lineNum: 2,
108+
filePath: "template.hbs", // Must be .hbs file for indented prefix detection
109+
inHbsCommentBlock: true, // Inside a {{! ... }} comment block
106110
expectedInfo: &CopyrightInfo{
107111
LineNumber: 2,
108112
OriginalLine: " Copyright IBM Corp. 2021, 2025",
@@ -117,7 +121,11 @@ func TestParseCopyrightLine(t *testing.T) {
117121

118122
for _, tt := range tests {
119123
t.Run(tt.name, func(t *testing.T) {
120-
result := parseCopyrightLine(tt.line, tt.lineNum, "file.go")
124+
filePath := tt.filePath
125+
if filePath == "" {
126+
filePath = "file.go"
127+
}
128+
result := parseCopyrightLine(tt.line, tt.lineNum, filePath, tt.inHbsCommentBlock)
121129

122130
if tt.expectNil {
123131
assert.Nil(t, result)
@@ -419,7 +427,7 @@ package main
419427

420428
func TestParseCopyrightLine_UnprefixedLicense(t *testing.T) {
421429
line := "Copyright IBM Corp. 2018, 2025"
422-
info := parseCopyrightLine(line, 1, "LICENSE")
430+
info := parseCopyrightLine(line, 1, "LICENSE", false)
423431
require.NotNil(t, info)
424432
assert.Equal(t, "IBM Corp.", info.Holder)
425433
assert.Equal(t, 2018, info.StartYear)
@@ -719,7 +727,7 @@ func TestParseCopyrightLine_StrictCopyrightCheck(t *testing.T) {
719727

720728
for _, tt := range tests {
721729
t.Run(tt.name, func(t *testing.T) {
722-
result := parseCopyrightLine(tt.line, 1, "file.go")
730+
result := parseCopyrightLine(tt.line, 1, "file.go", false)
723731
if tt.expectNil {
724732
assert.Nil(t, result, "Should return nil for non-copyright lines")
725733
} else {
@@ -760,7 +768,7 @@ func TestExtractCommentPrefix_AllFormats(t *testing.T) {
760768

761769
func TestParseCopyrightLine_InlineComment(t *testing.T) {
762770
line := "var x := 1 // Copyright IBM Corp. 2023"
763-
info := parseCopyrightLine(line, 1, "file.go")
771+
info := parseCopyrightLine(line, 1, "file.go", false)
764772
require.NotNil(t, info)
765773
assert.Equal(t, "IBM Corp.", info.Holder)
766774
assert.Equal(t, 2023, info.StartYear)

0 commit comments

Comments
 (0)