Skip to content

Commit a54916b

Browse files
committed
fix #4139: deduplicate repeated legal comments
1 parent dc60e60 commit a54916b

File tree

4 files changed

+110
-6
lines changed

4 files changed

+110
-6
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@
4848

4949
This fix was contributed by [@mxschmitt](https://github.com/mxschmitt).
5050

51+
* More concise output for repeated legal comments ([#4139](https://github.com/evanw/esbuild/issues/4139))
52+
53+
Some libraries have many files and also use the same legal comment text in all files. Previously esbuild would copy each legal comment to the output file. Starting with this release, legal comments duplicated across separate files will now be grouped in the output file by unique comment content.
54+
5155
* Fix path resolution edge case ([#4144](https://github.com/evanw/esbuild/issues/4144))
5256

5357
This fixes an edge case where esbuild's path resolution algorithm could deviate from node's path resolution algorithm. It involves a confusing situation where a directory shares the same file name as a file (but without the file extension). See the linked issue for specific details. This appears to be a case where esbuild is correctly following [node's published resolution algorithm](https://nodejs.org/api/modules.html#all-together) but where node itself is doing something different. Specifically the step `LOAD_AS_FILE` appears to be skipped when the input ends with `..`. This release changes esbuild's behavior for this edge case to match node's behavior.

internal/bundler_tests/bundler_default_test.go

+53
Original file line numberDiff line numberDiff line change
@@ -3833,6 +3833,59 @@ func TestLegalCommentsManyLinked(t *testing.T) {
38333833
})
38343834
}
38353835

3836+
// https://github.com/evanw/esbuild/issues/4139
3837+
func TestLegalCommentsMergeDuplicatesIssue4139(t *testing.T) {
3838+
default_suite.expectBundled(t, bundled{
3839+
files: map[string]string{
3840+
"/project/entry.js": `
3841+
import 'pkg/a'
3842+
import 'pkg/b'
3843+
import 'pkg/c'
3844+
import 'pkg/d'
3845+
`,
3846+
"/project/node_modules/pkg/a.js": `
3847+
/*!-----------------------------------------------------------------------------
3848+
* Copyright (c) Example Corporation. All rights reserved.
3849+
* Version: 1.2.3
3850+
* Released under the MIT license
3851+
* https://example.com/LICENSE.txt
3852+
*-----------------------------------------------------------------------------*/
3853+
`,
3854+
"/project/node_modules/pkg/b.js": `
3855+
/*!-----------------------------------------------------------------------------
3856+
* Copyright (c) Example Corporation. All rights reserved.
3857+
* Version: 1.2.3
3858+
* Released under the MIT license
3859+
* https://example.com/LICENSE.txt
3860+
*-----------------------------------------------------------------------------*/
3861+
`,
3862+
"/project/node_modules/pkg/c.js": `
3863+
//! some other comment
3864+
/*!-----------------------------------------------------------------------------
3865+
* Copyright (c) Example Corporation. All rights reserved.
3866+
* Version: 1.2.3
3867+
* Released under the MIT license
3868+
* https://example.com/LICENSE.txt
3869+
*-----------------------------------------------------------------------------*/
3870+
`,
3871+
"/project/node_modules/pkg/d.js": `
3872+
/*!-----------------------------------------------------------------------------
3873+
* Copyright (c) Example Corporation. All rights reserved.
3874+
* Version: 1.2.3
3875+
* Released under the MIT license
3876+
* https://example.com/LICENSE.txt
3877+
*-----------------------------------------------------------------------------*/
3878+
`,
3879+
},
3880+
entryPaths: []string{"/project/entry.js"},
3881+
options: config.Options{
3882+
Mode: config.ModeBundle,
3883+
AbsOutputFile: "/out.js",
3884+
LegalComments: config.LegalCommentsEndOfFile,
3885+
},
3886+
})
3887+
}
3888+
38363889
// The IIFE should not be an arrow function when targeting ES5
38373890
func TestIIFE_ES5(t *testing.T) {
38383891
default_suite.expectBundled(t, bundled{

internal/bundler_tests/snapshots/snapshots_default.txt

+25
Original file line numberDiff line numberDiff line change
@@ -3426,6 +3426,31 @@ some-pkg/css/index.css:
34263426
a{zoom:2}b{zoom:2}c{zoom:2}.some-other-pkg{zoom:2}
34273427
/*! For license information please see entry.css.LEGAL.txt */
34283428

3429+
================================================================================
3430+
TestLegalCommentsMergeDuplicatesIssue4139
3431+
---------- /out.js ----------
3432+
/*! Bundled license information:
3433+
3434+
pkg/a.js:
3435+
pkg/b.js:
3436+
pkg/d.js:
3437+
(*!-----------------------------------------------------------------------------
3438+
* Copyright (c) Example Corporation. All rights reserved.
3439+
* Version: 1.2.3
3440+
* Released under the MIT license
3441+
* https://example.com/LICENSE.txt
3442+
*-----------------------------------------------------------------------------*)
3443+
3444+
pkg/c.js:
3445+
(*! some other comment *)
3446+
(*!-----------------------------------------------------------------------------
3447+
* Copyright (c) Example Corporation. All rights reserved.
3448+
* Version: 1.2.3
3449+
* Released under the MIT license
3450+
* https://example.com/LICENSE.txt
3451+
*-----------------------------------------------------------------------------*)
3452+
*/
3453+
34293454
================================================================================
34303455
TestLegalCommentsModifyIndent
34313456
---------- /out/entry.js ----------

internal/linker/linker.go

+28-6
Original file line numberDiff line numberDiff line change
@@ -6526,8 +6526,8 @@ func (c *linkerContext) maybeAppendLegalComments(
65266526
}
65276527

65286528
type thirdPartyEntry struct {
6529-
packagePath string
6530-
comments []string
6529+
packagePaths []string
6530+
comments []string
65316531
}
65326532

65336533
var uniqueFirstPartyComments []string
@@ -6573,8 +6573,8 @@ func (c *linkerContext) maybeAppendLegalComments(
65736573

65746574
if packagePath != "" {
65756575
thirdPartyComments = append(thirdPartyComments, thirdPartyEntry{
6576-
packagePath: packagePath,
6577-
comments: entry.comments,
6576+
packagePaths: []string{packagePath},
6577+
comments: entry.comments,
65786578
})
65796579
} else {
65806580
for _, comment := range entry.comments {
@@ -6586,6 +6586,22 @@ func (c *linkerContext) maybeAppendLegalComments(
65866586
}
65876587
}
65886588

6589+
// Merge package paths with identical comments
6590+
identical := make(map[string]int)
6591+
end := 0
6592+
for _, entry := range thirdPartyComments {
6593+
key := strings.Join(entry.comments, "\x00")
6594+
if index, ok := identical[key]; ok {
6595+
existing := &thirdPartyComments[index]
6596+
existing.packagePaths = append(existing.packagePaths, entry.packagePaths...)
6597+
} else {
6598+
identical[key] = end
6599+
thirdPartyComments[end] = entry
6600+
end++
6601+
}
6602+
}
6603+
thirdPartyComments = thirdPartyComments[:end]
6604+
65896605
switch legalComments {
65906606
case config.LegalCommentsEndOfFile:
65916607
for _, comment := range uniqueFirstPartyComments {
@@ -6596,7 +6612,10 @@ func (c *linkerContext) maybeAppendLegalComments(
65966612
if len(thirdPartyComments) > 0 {
65976613
j.AddString("/*! Bundled license information:\n")
65986614
for _, entry := range thirdPartyComments {
6599-
j.AddString(fmt.Sprintf("\n%s:\n", helpers.EscapeClosingTag(entry.packagePath, slashTag)))
6615+
j.AddString("\n")
6616+
for _, packagePath := range entry.packagePaths {
6617+
j.AddString(fmt.Sprintf("%s:\n", helpers.EscapeClosingTag(packagePath, slashTag)))
6618+
}
66006619
for _, comment := range entry.comments {
66016620
comment = helpers.EscapeClosingTag(comment, slashTag)
66026621
if strings.HasPrefix(comment, "//") {
@@ -6623,7 +6642,10 @@ func (c *linkerContext) maybeAppendLegalComments(
66236642
}
66246643
jComments.AddString("Bundled license information:\n")
66256644
for _, entry := range thirdPartyComments {
6626-
jComments.AddString(fmt.Sprintf("\n%s:\n", entry.packagePath))
6645+
jComments.AddString("\n")
6646+
for _, packagePath := range entry.packagePaths {
6647+
jComments.AddString(fmt.Sprintf("%s:\n", packagePath))
6648+
}
66276649
for _, comment := range entry.comments {
66286650
jComments.AddString(fmt.Sprintf(" %s\n", strings.ReplaceAll(comment, "\n", "\n ")))
66296651
}

0 commit comments

Comments
 (0)