Skip to content

Commit

Permalink
fix #3306: handle lack of a trailing glob wildcard
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Aug 11, 2023
1 parent 83917cf commit be9e098
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

* Fix glob patterns matching extra stuff at the end ([#3306](https://github.com/evanw/esbuild/issues/3306))

Previously glob patterns such as `./*.js` would incorrectly behave like `./*.js*` during path matching (also matching `.js.map` files, for example). This was never intentional behavior, and has now been fixed.

* Change the permissions of esbuild's generated output files ([#3285](https://github.com/evanw/esbuild/issues/3285))

This release changes the permissions of the output files that esbuild generates to align with the default behavior of node's [`fs.writeFileSync`](https://nodejs.org/api/fs.html#fswritefilesyncfile-data-options) function. Since most tools written in JavaScript use `fs.writeFileSync`, this should make esbuild more consistent with how other JavaScript build tools behave.
Expand Down
70 changes: 70 additions & 0 deletions internal/bundler_tests/bundler_glob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,73 @@ func TestGlobEntryPointAbsPath(t *testing.T) {
},
})
}

func TestGlobWildcardSlash(t *testing.T) {
glob_suite.expectBundled(t, bundled{
files: map[string]string{
"/entry.js": `
const ab = Math.random() < 0.5 ? 'a.js' : 'b.js'
console.log({
concat: {
require: require('./src/' + ab + '.js'),
import: import('./src/' + ab + '.js'),
},
template: {
require: require(` + "`./src/${ab}.js`" + `),
import: import(` + "`./src/${ab}.js`" + `),
},
})
`,

"/src/file-a.js": `module.exports = 'a'`,
"/src/file-b.js": `module.exports = 'b'`,
"/src/file-a.js.map": `DO NOT BUNDLE`,
"/src/file-b.js.map": `DO NOT BUNDLE`,

"/src/nested/dir/file-a.js": `module.exports = 'a'`,
"/src/nested/dir/file-b.js": `module.exports = 'b'`,
"/src/nested/dir/file-a.js.map": `DO NOT BUNDLE`,
"/src/nested/dir/file-b.js.map": `DO NOT BUNDLE`,
},
entryPaths: []string{"/entry.js"},
options: config.Options{
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
},
})
}

func TestGlobWildcardNoSlash(t *testing.T) {
glob_suite.expectBundled(t, bundled{
files: map[string]string{
"/entry.js": `
const ab = Math.random() < 0.5 ? 'a.js' : 'b.js'
console.log({
concat: {
require: require('./src/file-' + ab + '.js'),
import: import('./src/file-' + ab + '.js'),
},
template: {
require: require(` + "`./src/file-${ab}.js`" + `),
import: import(` + "`./src/file-${ab}.js`" + `),
},
})
`,

"/src/file-a.js": `module.exports = 'a'`,
"/src/file-b.js": `module.exports = 'b'`,
"/src/file-a.js.map": `DO NOT BUNDLE`,
"/src/file-b.js.map": `DO NOT BUNDLE`,

"/src/nested/dir/file-a.js": `DO NOT BUNDLE`,
"/src/nested/dir/file-b.js": `DO NOT BUNDLE`,
"/src/nested/dir/file-a.js.map": `DO NOT BUNDLE`,
"/src/nested/dir/file-b.js.map": `DO NOT BUNDLE`,
},
entryPaths: []string{"/entry.js"},
options: config.Options{
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
},
})
}
102 changes: 102 additions & 0 deletions internal/bundler_tests/snapshots/snapshots_glob.txt
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,105 @@ console.log({
import: globImport_src_json(`./src/${ab}.json`)
}
});

================================================================================
TestGlobWildcardNoSlash
---------- /out.js ----------
// src/file-a.js
var require_file_a = __commonJS({
"src/file-a.js"(exports, module) {
module.exports = "a";
}
});

// src/file-b.js
var require_file_b = __commonJS({
"src/file-b.js"(exports, module) {
module.exports = "b";
}
});

// require("./src/file-*.js") in entry.js
var globRequire_src_file_js = __glob({
"./src/file-a.js": () => require_file_a(),
"./src/file-b.js": () => require_file_b()
});

// import("./src/file-*.js") in entry.js
var globImport_src_file_js = __glob({
"./src/file-a.js": () => Promise.resolve().then(() => __toESM(require_file_a())),
"./src/file-b.js": () => Promise.resolve().then(() => __toESM(require_file_b()))
});

// entry.js
var ab = Math.random() < 0.5 ? "a.js" : "b.js";
console.log({
concat: {
require: globRequire_src_file_js("./src/file-" + ab + ".js"),
import: globImport_src_file_js("./src/file-" + ab + ".js")
},
template: {
require: globRequire_src_file_js(`./src/file-${ab}.js`),
import: globImport_src_file_js(`./src/file-${ab}.js`)
}
});

================================================================================
TestGlobWildcardSlash
---------- /out.js ----------
// src/file-a.js
var require_file_a = __commonJS({
"src/file-a.js"(exports, module) {
module.exports = "a";
}
});

// src/file-b.js
var require_file_b = __commonJS({
"src/file-b.js"(exports, module) {
module.exports = "b";
}
});

// src/nested/dir/file-a.js
var require_file_a2 = __commonJS({
"src/nested/dir/file-a.js"(exports, module) {
module.exports = "a";
}
});

// src/nested/dir/file-b.js
var require_file_b2 = __commonJS({
"src/nested/dir/file-b.js"(exports, module) {
module.exports = "b";
}
});

// require("./src/**/*.js") in entry.js
var globRequire_src_js = __glob({
"./src/file-a.js": () => require_file_a(),
"./src/file-b.js": () => require_file_b(),
"./src/nested/dir/file-a.js": () => require_file_a2(),
"./src/nested/dir/file-b.js": () => require_file_b2()
});

// import("./src/**/*.js") in entry.js
var globImport_src_js = __glob({
"./src/file-a.js": () => Promise.resolve().then(() => __toESM(require_file_a())),
"./src/file-b.js": () => Promise.resolve().then(() => __toESM(require_file_b())),
"./src/nested/dir/file-a.js": () => Promise.resolve().then(() => __toESM(require_file_a2())),
"./src/nested/dir/file-b.js": () => Promise.resolve().then(() => __toESM(require_file_b2()))
});

// entry.js
var ab = Math.random() < 0.5 ? "a.js" : "b.js";
console.log({
concat: {
require: globRequire_src_js("./src/" + ab + ".js"),
import: globImport_src_js("./src/" + ab + ".js")
},
template: {
require: globRequire_src_js(`./src/${ab}.js`),
import: globImport_src_js(`./src/${ab}.js`)
}
});
5 changes: 3 additions & 2 deletions internal/resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -694,12 +694,13 @@ func (res *Resolver) ResolveGlob(sourceDir string, importPathPattern []helpers.G
prefix = prefix[1:] // Move over the "/" after a globstar
}
sb.WriteString(regexp.QuoteMeta(prefix))
if part.Wildcard == helpers.GlobAllIncludingSlash {
switch part.Wildcard {
case helpers.GlobAllIncludingSlash:
// It's a globstar, so match zero or more path segments
sb.WriteString("(?:[^/]*(?:/|$))*")
canMatchOnSlash = true
wasGlobStar = true
} else {
case helpers.GlobAllExceptSlash:
// It's not a globstar, so only match one path segment
sb.WriteString("[^/]*")
wasGlobStar = false
Expand Down

0 comments on commit be9e098

Please sign in to comment.