mirror of
https://github.com/oven-sh/bun
synced 2026-02-14 04:49:06 +00:00
implement publicHoistPattern and hoistPattern (#23567)
### What does this PR do? Adds support for `publicHoistPattern` in `bunfig.toml` and `public-hoist-pattern` from `.npmrc`. This setting allows you to select transitive packages to hoist to the root node_modules making them available for all workspace packages. ```toml [install] # can be a string publicHoistPattern = "@types*" # or an array publicHoistPattern = [ "@types*", "*eslint*" ] ``` `publicHoistPattern` only affects the isolated linker. --- Adds `hoistPattern`. `hoistPattern` is the same as `publicHoistPattern`, but applies to the `node_modules/.bun/node_modules` directory instead of the root node_modules. Also the default value of `hoistPattern` is `*` (everything is hoisted to `node_modules/.bun/node_modules` by default). --- Fixes a determinism issue constructing the `node_modules/.bun/node_modules` directory. --- closes #23481 closes #6160 closes #23548 ### How did you verify your code works? Added tests for - [x] only include patterns - [x] only exclude patterns - [x] mix of include and exclude - [x] errors for unexpected expression types - [x] excluding direct dependency (should still include) - [x] match all with `*` - [x] string and array expression types --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
122
src/string/escapeRegExp.zig
Normal file
122
src/string/escapeRegExp.zig
Normal file
@@ -0,0 +1,122 @@
|
||||
const special_characters = "|\\{}()[]^$+*?.-";
|
||||
|
||||
pub fn escapeRegExp(input: []const u8, writer: anytype) @TypeOf(writer).Error!void {
|
||||
var remain = input;
|
||||
|
||||
while (strings.indexOfAny(remain, special_characters)) |i| {
|
||||
try writer.writeAll(remain[0..i]);
|
||||
switch (remain[i]) {
|
||||
'|',
|
||||
'\\',
|
||||
'{',
|
||||
'}',
|
||||
'(',
|
||||
')',
|
||||
'[',
|
||||
']',
|
||||
'^',
|
||||
'$',
|
||||
'+',
|
||||
'*',
|
||||
'?',
|
||||
'.',
|
||||
=> |c| try writer.writeAll(&.{ '\\', c }),
|
||||
'-' => try writer.writeAll("\\x2d"),
|
||||
else => |c| {
|
||||
if (comptime Environment.isDebug) {
|
||||
unreachable;
|
||||
}
|
||||
try writer.writeByte(c);
|
||||
},
|
||||
}
|
||||
remain = remain[i + 1 ..];
|
||||
}
|
||||
|
||||
try writer.writeAll(remain);
|
||||
}
|
||||
|
||||
/// '*' becomes '.*' instead of '\\*'
|
||||
pub fn escapeRegExpForPackageNameMatching(input: []const u8, writer: anytype) @TypeOf(writer).Error!void {
|
||||
var remain = input;
|
||||
|
||||
while (strings.indexOfAny(remain, special_characters)) |i| {
|
||||
try writer.writeAll(remain[0..i]);
|
||||
switch (remain[i]) {
|
||||
'|',
|
||||
'\\',
|
||||
'{',
|
||||
'}',
|
||||
'(',
|
||||
')',
|
||||
'[',
|
||||
']',
|
||||
'^',
|
||||
'$',
|
||||
'+',
|
||||
'?',
|
||||
'.',
|
||||
=> |c| try writer.writeAll(&.{ '\\', c }),
|
||||
'*' => try writer.writeAll(".*"),
|
||||
'-' => try writer.writeAll("\\x2d"),
|
||||
else => |c| {
|
||||
if (comptime Environment.isDebug) {
|
||||
unreachable;
|
||||
}
|
||||
try writer.writeByte(c);
|
||||
},
|
||||
}
|
||||
remain = remain[i + 1 ..];
|
||||
}
|
||||
|
||||
try writer.writeAll(remain);
|
||||
}
|
||||
|
||||
pub fn jsEscapeRegExp(global: *JSGlobalObject, call_frame: *jsc.CallFrame) JSError!JSValue {
|
||||
const input_value = call_frame.argument(0);
|
||||
|
||||
if (!input_value.isString()) {
|
||||
return global.throw("expected string argument", .{});
|
||||
}
|
||||
|
||||
var input = try input_value.toSlice(global, bun.default_allocator);
|
||||
defer input.deinit();
|
||||
|
||||
var buf: bun.collections.ArrayListDefault(u8) = .init();
|
||||
defer buf.deinit();
|
||||
|
||||
try escapeRegExp(input.slice(), buf.writer());
|
||||
|
||||
var output = String.cloneUTF8(buf.items());
|
||||
|
||||
return output.toJS(global);
|
||||
}
|
||||
|
||||
pub fn jsEscapeRegExpForPackageNameMatching(global: *JSGlobalObject, call_frame: *jsc.CallFrame) JSError!JSValue {
|
||||
const input_value = call_frame.argument(0);
|
||||
|
||||
if (!input_value.isString()) {
|
||||
return global.throw("expected string argument", .{});
|
||||
}
|
||||
|
||||
var input = try input_value.toSlice(global, bun.default_allocator);
|
||||
defer input.deinit();
|
||||
|
||||
var buf: bun.collections.ArrayListDefault(u8) = .init();
|
||||
defer buf.deinit();
|
||||
|
||||
try escapeRegExpForPackageNameMatching(input.slice(), buf.writer());
|
||||
|
||||
var output = String.cloneUTF8(buf.items());
|
||||
|
||||
return output.toJS(global);
|
||||
}
|
||||
|
||||
const bun = @import("bun");
|
||||
const Environment = bun.Environment;
|
||||
const JSError = bun.JSError;
|
||||
const String = bun.String;
|
||||
const strings = bun.strings;
|
||||
|
||||
const jsc = bun.jsc;
|
||||
const JSGlobalObject = jsc.JSGlobalObject;
|
||||
const JSValue = jsc.JSValue;
|
||||
@@ -2306,6 +2306,9 @@ pub const visibleCodepointWidthType = visible_.visibleCodepointWidthType;
|
||||
pub const escapeHTMLForLatin1Input = escapeHTML_.escapeHTMLForLatin1Input;
|
||||
pub const escapeHTMLForUTF16Input = escapeHTML_.escapeHTMLForUTF16Input;
|
||||
|
||||
pub const escapeRegExp = escapeRegExp_.escapeRegExp;
|
||||
pub const escapeRegExpForPackageNameMatching = escapeRegExp_.escapeRegExpForPackageNameMatching;
|
||||
|
||||
pub const addNTPathPrefix = paths_.addNTPathPrefix;
|
||||
pub const addNTPathPrefixIfNeeded = paths_.addNTPathPrefixIfNeeded;
|
||||
pub const addLongPathPrefix = paths_.addLongPathPrefix;
|
||||
@@ -2347,6 +2350,7 @@ pub const CodePoint = i32;
|
||||
const string = []const u8;
|
||||
|
||||
const escapeHTML_ = @import("./immutable/escapeHTML.zig");
|
||||
const escapeRegExp_ = @import("./escapeRegExp.zig");
|
||||
const paths_ = @import("./immutable/paths.zig");
|
||||
const std = @import("std");
|
||||
const unicode = @import("./immutable/unicode.zig");
|
||||
|
||||
Reference in New Issue
Block a user