diff --git a/licensecheck/update.go b/licensecheck/update.go index 3d6715a..232761e 100644 --- a/licensecheck/update.go +++ b/licensecheck/update.go @@ -39,14 +39,30 @@ func extractAllCopyrightInfo(filePath string) ([]*CopyrightInfo, error) { lineNum := 0 var copyrights []*CopyrightInfo + // Track if we're inside a {{! ... }} comment block for .hbs files + isHbsFile := strings.ToLower(filepath.Ext(filePath)) == ".hbs" + inHbsCommentBlock := false + // Scan entire file for all copyright statements for scanner.Scan() { lineNum++ line := scanner.Text() + // For .hbs files, track comment block state + if isHbsFile { + // Check for start of multi-line comment block: {{! at start (not closed on same line) + if strings.Contains(line, "{{!") && !strings.Contains(line, "}}") { + inHbsCommentBlock = true + } + // Check for end of comment block + if inHbsCommentBlock && strings.Contains(line, "}}") { + inHbsCommentBlock = false + } + } + // Check if line contains "copyright" if strings.Contains(strings.ToLower(line), "copyright") { - info := parseCopyrightLine(line, lineNum, filePath) + info := parseCopyrightLine(line, lineNum, filePath, inHbsCommentBlock) if info != nil { copyrights = append(copyrights, info) } @@ -57,11 +73,15 @@ func extractAllCopyrightInfo(filePath string) ([]*CopyrightInfo, error) { } // parseCopyrightLine extracts copyright details from a line -func parseCopyrightLine(line string, lineNum int, filePath string) *CopyrightInfo { - // 1. Determine the prefix and content source +// parseCopyrightLine extracts copyright details from a line +// inHbsCommentBlock indicates if we're inside a {{! ... }} block (for .hbs files) +func parseCopyrightLine(line string, lineNum int, filePath string, inHbsCommentBlock bool) *CopyrightInfo { + // 1. Determine the prefix and content source (file-aware) + // Pass inHbsCommentBlock to only allow indented prefixes inside comment blocks + prefixes := getCommentPrefixesForFile(filePath, inHbsCommentBlock) bestIdx := -1 bestPrefix := "" - for _, p := range commentPrefixes { + for _, p := range prefixes { if idx := strings.Index(line, p); idx >= 0 { if bestIdx == -1 || idx < bestIdx { bestIdx = idx @@ -251,10 +271,27 @@ var commentPrefixes = []string{ "// ", "//", "# ", "#", "% ", "%", - " ", "* ", "*", } +// hbsIndentedPrefixes are additional prefixes for .hbs files (multi-line {{! }} blocks) +var hbsIndentedPrefixes = []string{ + " ", // Two spaces (common indentation inside {{! }} blocks) + "\t", // Tab indentation +} + +// getCommentPrefixesForFile returns the appropriate comment prefixes for a file type +// inHbsCommentBlock indicates if we're inside a {{! ... }} block in .hbs files +func getCommentPrefixesForFile(filePath string, inHbsCommentBlock bool) []string { + ext := strings.ToLower(filepath.Ext(filePath)) + if ext == ".hbs" && inHbsCommentBlock { + // Only apply indented prefixes when inside a {{! ... }} comment block + // This prevents matching JavaScript code elsewhere in the file + return append(commentPrefixes, hbsIndentedPrefixes...) + } + return commentPrefixes +} + // hasSpecialFirstLine checks if the file content starts with a special line // that should be preserved (like shebangs, XML declarations, etc.) func hasSpecialFirstLine(content []byte, filePath string) bool { diff --git a/licensecheck/update_test.go b/licensecheck/update_test.go index d534de5..ed8341b 100644 --- a/licensecheck/update_test.go +++ b/licensecheck/update_test.go @@ -17,11 +17,13 @@ import ( func TestParseCopyrightLine(t *testing.T) { tests := []struct { - name string - line string - lineNum int - expectedInfo *CopyrightInfo - expectNil bool + name string + line string + lineNum int + filePath string // optional, defaults to "file.go" + inHbsCommentBlock bool // true if inside {{! ... }} block + expectedInfo *CopyrightInfo + expectNil bool }{ { name: "Simple copyright with single year", @@ -100,9 +102,11 @@ func TestParseCopyrightLine(t *testing.T) { }, }, { - name: "Handlebars indented copyright", - line: " Copyright IBM Corp. 2021, 2025", - lineNum: 2, + name: "Handlebars indented copyright", + line: " Copyright IBM Corp. 2021, 2025", + lineNum: 2, + filePath: "template.hbs", // Must be .hbs file for indented prefix detection + inHbsCommentBlock: true, // Inside a {{! ... }} comment block expectedInfo: &CopyrightInfo{ LineNumber: 2, OriginalLine: " Copyright IBM Corp. 2021, 2025", @@ -117,7 +121,11 @@ func TestParseCopyrightLine(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := parseCopyrightLine(tt.line, tt.lineNum, "file.go") + filePath := tt.filePath + if filePath == "" { + filePath = "file.go" + } + result := parseCopyrightLine(tt.line, tt.lineNum, filePath, tt.inHbsCommentBlock) if tt.expectNil { assert.Nil(t, result) @@ -419,7 +427,7 @@ package main func TestParseCopyrightLine_UnprefixedLicense(t *testing.T) { line := "Copyright IBM Corp. 2018, 2025" - info := parseCopyrightLine(line, 1, "LICENSE") + info := parseCopyrightLine(line, 1, "LICENSE", false) require.NotNil(t, info) assert.Equal(t, "IBM Corp.", info.Holder) assert.Equal(t, 2018, info.StartYear) @@ -719,7 +727,7 @@ func TestParseCopyrightLine_StrictCopyrightCheck(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := parseCopyrightLine(tt.line, 1, "file.go") + result := parseCopyrightLine(tt.line, 1, "file.go", false) if tt.expectNil { assert.Nil(t, result, "Should return nil for non-copyright lines") } else { @@ -760,7 +768,7 @@ func TestExtractCommentPrefix_AllFormats(t *testing.T) { func TestParseCopyrightLine_InlineComment(t *testing.T) { line := "var x := 1 // Copyright IBM Corp. 2023" - info := parseCopyrightLine(line, 1, "file.go") + info := parseCopyrightLine(line, 1, "file.go", false) require.NotNil(t, info) assert.Equal(t, "IBM Corp.", info.Holder) assert.Equal(t, 2023, info.StartYear)