diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a5a059d988..aea1d7c4f16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,6 +74,10 @@ The change in the previous release to forbid duplicate function declarations in certain cases accidentally forbid some edge cases that should have been allowed. Specifically duplicate function declarations are forbidden in nested blocks in strict mode and at the top level of modules, but are allowed when they are declared at the top level of function bodies. This release fixes the regression by re-allowing the last case. +* Allow package subpaths with `alias` ([#2715](https://github.com/evanw/esbuild/issues/2715)) + + Previously the names passed to the `alias` feature had to be the name of a package (with or without a package scope). With this release, you can now also use the `alias` feature with package subpaths. So for example you can now create an alias that substitutes `@org/pkg/lib` with something else. + ## 0.16.9 * Update to Unicode 15.0.0 diff --git a/internal/bundler_tests/bundler_default_test.go b/internal/bundler_tests/bundler_default_test.go index e51ad7d3012..5deddbb1e16 100644 --- a/internal/bundler_tests/bundler_default_test.go +++ b/internal/bundler_tests/bundler_default_test.go @@ -7182,18 +7182,22 @@ func TestPackageAlias(t *testing.T) { import "@abs-path/pkg7/foo" import "@scope-only/pkg8" import "slash/" + import "prefix-foo" + import "@scope/prefix-foo" `, - "/nested3/index.js": `import "pkg3"`, - "/nested3/node_modules/alias3/index.js": `test failure`, - "/node_modules/alias1/index.js": `console.log(1)`, - "/node_modules/alias2/foo.js": `console.log(2)`, - "/node_modules/alias3/index.js": `console.log(3)`, - "/node_modules/alias4/index.js": `console.log(4)`, - "/node_modules/alias5/foo.js": `console.log(5)`, - "/alias6/dir/index.js": `console.log(6)`, - "/alias7/dir/foo/index.js": `console.log(7)`, - "/alias8/dir/pkg8/index.js": `console.log(8)`, - "/alias9/some/file.js": `console.log(9)`, + "/nested3/index.js": `import "pkg3"`, + "/nested3/node_modules/alias3/index.js": `test failure`, + "/node_modules/alias1/index.js": `console.log(1)`, + "/node_modules/alias2/foo.js": `console.log(2)`, + "/node_modules/alias3/index.js": `console.log(3)`, + "/node_modules/alias4/index.js": `console.log(4)`, + "/node_modules/alias5/foo.js": `console.log(5)`, + "/alias6/dir/index.js": `console.log(6)`, + "/alias7/dir/foo/index.js": `console.log(7)`, + "/alias8/dir/pkg8/index.js": `console.log(8)`, + "/alias9/some/file.js": `console.log(9)`, + "/node_modules/prefix-foo/index.js": `console.log(10)`, + "/node_modules/@scope/prefix-foo/index.js": `console.log(11)`, }, entryPaths: []string{"/entry.js"}, options: config.Options{ @@ -7209,6 +7213,8 @@ func TestPackageAlias(t *testing.T) { "@abs-path/pkg7": `/alias7/dir`, "@scope-only": "/alias8/dir", "slash": "/alias9/some/file.js", + "prefix": "alias10", + "@scope/prefix": "alias11", }, }, }) diff --git a/internal/bundler_tests/snapshots/snapshots_default.txt b/internal/bundler_tests/snapshots/snapshots_default.txt index befc369da74..de720ff718d 100644 --- a/internal/bundler_tests/snapshots/snapshots_default.txt +++ b/internal/bundler_tests/snapshots/snapshots_default.txt @@ -4088,6 +4088,12 @@ console.log(8); // alias9/some/file.js console.log(9); +// node_modules/prefix-foo/index.js +console.log(10); + +// node_modules/@scope/prefix-foo/index.js +console.log(11); + ================================================================================ TestQuotedProperty ---------- /out/entry.js ---------- diff --git a/pkg/api/api_impl.go b/pkg/api/api_impl.go index ce9607ba3bf..bc3ba4ecf7f 100644 --- a/pkg/api/api_impl.go +++ b/pkg/api/api_impl.go @@ -6,6 +6,7 @@ import ( "math" "math/rand" "os" + "path" "regexp" "sort" "strconv" @@ -488,28 +489,24 @@ func validateAlias(log logger.Log, fs fs.FS, alias map[string]string) map[string // Valid alias names: // "foo" + // "foo/bar" // "@foo" // "@foo/bar" + // "@foo/bar/baz" // // Invalid alias names: // "./foo" - // "foo/bar" + // "../foo" + // "/foo" + // "C:\\foo" + // ".foo" + // "foo/" // "@foo/" - // "@foo/bar/baz" + // "foo/../bar" // - if !strings.HasPrefix(old, ".") && !strings.HasPrefix(old, "/") && !fs.IsAbs(old) { - slash := strings.IndexByte(old, '/') - isScope := strings.HasPrefix(old, "@") - if slash != -1 && isScope { - pkgAfterScope := old[slash+1:] - if slash2 := strings.IndexByte(pkgAfterScope, '/'); slash2 == -1 && pkgAfterScope != "" { - valid[old] = new - continue - } - } else if slash == -1 { - valid[old] = new - continue - } + if !strings.HasPrefix(old, ".") && !strings.HasPrefix(old, "/") && !fs.IsAbs(old) && path.Clean(strings.ReplaceAll(old, "\\", "/")) == old { + valid[old] = new + continue } log.AddError(nil, logger.Range{}, fmt.Sprintf("Invalid alias name: %q", old)) diff --git a/scripts/js-api-tests.js b/scripts/js-api-tests.js index 8ef7f8d063c..cfd396ac348 100644 --- a/scripts/js-api-tests.js +++ b/scripts/js-api-tests.js @@ -157,14 +157,19 @@ let buildTests = { await Promise.all([ valid('foo'), - valid('@scope'), - valid('@scope/foo'), + valid('foo/bar'), + valid('@foo'), + valid('@foo/bar'), + valid('@foo/bar/baz'), - invalid('foo/bar'), - invalid('/foo'), invalid('./foo'), - invalid('@scope/'), - invalid('@scope/foo/bar'), + invalid('../foo'), + invalid('/foo'), + invalid('C:\\foo'), + invalid('.foo'), + invalid('foo/'), + invalid('@foo/'), + invalid('foo/../bar'), ]) },