Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 42 additions & 5 deletions licensecheck/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
32 changes: 20 additions & 12 deletions licensecheck/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down
Loading