From 83039b8d13d40067227b917b5a730d3977e5b738 Mon Sep 17 00:00:00 2001 From: btea <2356281422@qq.com> Date: Mon, 9 Nov 2026 15:51:19 +0800 Subject: [PATCH 1/2] feat(pluginutils): add `wordRegex` --- packages/pluginutils/README.md | 16 ++++++++++++++++ packages/pluginutils/src/filterUtils.ts | 4 ++++ packages/pluginutils/src/index.ts | 8 +++++--- packages/pluginutils/test/filterUtils.ts | 21 ++++++++++++++++++++- packages/pluginutils/types/index.d.ts | 9 +++++++++ 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/packages/pluginutils/README.md b/packages/pluginutils/README.md index 8c43672ec..d6540b321 100755 --- a/packages/pluginutils/README.md +++ b/packages/pluginutils/README.md @@ -240,6 +240,22 @@ exactRegex(['foo', 'bar']); // /^(?:foo|bar)$/ exactRegex('foo(bar)', 'i'); // /^foo\(bar\)$/i ``` +### wordRegex + +Constructs a RegExp that matches the specified string with word boundaries. This is useful when matching a complete word-like token, such as `node_modules` but not `node_modulesa`. + +Parameters: `(str: String, flags?: String)`
+Returns: `RegExp` + +#### Usage + +```js +import { wordRegex } from '@rollup/pluginutils'; + +wordRegex('node_modules'); // /\bnode_modules\b/ +wordRegex('foo.bar', 'i'); // /\bfoo\.bar\b/i +``` + ### makeLegalIdentifier Constructs a bundle-safe identifier from a `String`. diff --git a/packages/pluginutils/src/filterUtils.ts b/packages/pluginutils/src/filterUtils.ts index dedda12ef..16ceeb44c 100644 --- a/packages/pluginutils/src/filterUtils.ts +++ b/packages/pluginutils/src/filterUtils.ts @@ -10,6 +10,10 @@ export function suffixRegex(str: string | string[], flags?: string): RegExp { return new RegExp(`${combineMultipleStrings(str)}$`, flags); } +export function wordRegex(str: string, flags?: string): RegExp { + return new RegExp(`\\b${escapeRegex(str)}\\b`, flags); +} + const escapeRegexRE = /[-/\\^$*+?.()|[\]{}]/g; function escapeRegex(str: string): string { return str.replace(escapeRegexRE, '\\$&'); diff --git a/packages/pluginutils/src/index.ts b/packages/pluginutils/src/index.ts index 51a02b583..27f62674e 100644 --- a/packages/pluginutils/src/index.ts +++ b/packages/pluginutils/src/index.ts @@ -5,7 +5,7 @@ import dataToEsm from './dataToEsm'; import extractAssignedNames from './extractAssignedNames'; import makeLegalIdentifier from './makeLegalIdentifier'; import normalizePath from './normalizePath'; -import { exactRegex, prefixRegex, suffixRegex } from './filterUtils'; +import { exactRegex, prefixRegex, suffixRegex, wordRegex } from './filterUtils'; export { addExtension, @@ -17,7 +17,8 @@ export { makeLegalIdentifier, normalizePath, prefixRegex, - suffixRegex + suffixRegex, + wordRegex }; // TODO: remove this in next major @@ -31,5 +32,6 @@ export default { makeLegalIdentifier, normalizePath, prefixRegex, - suffixRegex + suffixRegex, + wordRegex }; diff --git a/packages/pluginutils/test/filterUtils.ts b/packages/pluginutils/test/filterUtils.ts index fe55acb1d..1924adab9 100644 --- a/packages/pluginutils/test/filterUtils.ts +++ b/packages/pluginutils/test/filterUtils.ts @@ -1,4 +1,4 @@ -import { exactRegex, prefixRegex, suffixRegex } from '../'; +import { exactRegex, prefixRegex, suffixRegex, wordRegex } from '../'; test('exactRegex supports without flag parameter', () => { expect(exactRegex('foo').toString()).toBe('/^foo$/'); @@ -71,3 +71,22 @@ test('suffixRegex escapes special characters for Regex', () => { test('suffixRegex escapes special characters with multiple string for Regex', () => { expect(suffixRegex(['foo(bar)', 'baz(qux)']).toString()).toBe('/(?:foo\\(bar\\)|baz\\(qux\\))$/'); }); + +test('wordRegex matches complete word-like tokens', () => { + const regex = wordRegex('node_modules'); + + expect(regex.toString()).toBe('/\\bnode_modules\\b/'); + expect(regex.test('node_modules')).toBe(true); + expect(regex.test('/node_modules/')).toBe(true); + expect(regex.test('foo/node_modules/bar')).toBe(true); + expect(regex.test('node_modulesa')).toBe(false); + expect(regex.test('anode_modules')).toBe(false); +}); + +test('wordRegex supports flags and escapes special characters', () => { + const regex = wordRegex('foo.bar', 'i'); + + expect(regex.toString()).toBe('/\\bfoo\\.bar\\b/i'); + expect(regex.test('FOO.BAR')).toBe(true); + expect(regex.test('foo.barx')).toBe(false); +}); diff --git a/packages/pluginutils/types/index.d.ts b/packages/pluginutils/types/index.d.ts index ed3c8fdb3..60fa4c11c 100755 --- a/packages/pluginutils/types/index.d.ts +++ b/packages/pluginutils/types/index.d.ts @@ -99,6 +99,13 @@ export function prefixRegex(str: string | string[], flags?: string): RegExp; */ export function suffixRegex(str: string | string[], flags?: string): RegExp; +/** + * Constructs a RegExp that matches the specified string with word boundaries. + * @param str the string to match. + * @param flags flags for the RegExp. + */ +export function wordRegex(str: string, flags?: string): RegExp; + export type AddExtension = typeof addExtension; export type AttachScopes = typeof attachScopes; export type CreateFilter = typeof createFilter; @@ -109,6 +116,7 @@ export type NormalizePath = typeof normalizePath; export type DataToEsm = typeof dataToEsm; export type PrefixRegex = typeof prefixRegex; export type SuffixRegex = typeof suffixRegex; +export type WordRegex = typeof wordRegex; declare const defaultExport: { addExtension: AddExtension; @@ -121,5 +129,6 @@ declare const defaultExport: { normalizePath: NormalizePath; prefixRegex: PrefixRegex; suffixRegex: SuffixRegex; + wordRegex: WordRegex; }; export default defaultExport; From 16d898d3d87ce37b9fa6732e19226117e55911ef Mon Sep 17 00:00:00 2001 From: btea <2356281422@qq.com> Date: Mon, 9 Nov 2026 16:15:28 +0800 Subject: [PATCH 2/2] fix: update --- packages/pluginutils/src/filterUtils.ts | 2 +- packages/pluginutils/test/filterUtils.ts | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/pluginutils/src/filterUtils.ts b/packages/pluginutils/src/filterUtils.ts index 16ceeb44c..fd40e2da9 100644 --- a/packages/pluginutils/src/filterUtils.ts +++ b/packages/pluginutils/src/filterUtils.ts @@ -14,7 +14,7 @@ export function wordRegex(str: string, flags?: string): RegExp { return new RegExp(`\\b${escapeRegex(str)}\\b`, flags); } -const escapeRegexRE = /[-/\\^$*+?.()|[\]{}]/g; +const escapeRegexRE = /[/\\^$*+?.()|[\]{}]/g; function escapeRegex(str: string): string { return str.replace(escapeRegexRE, '\\$&'); } diff --git a/packages/pluginutils/test/filterUtils.ts b/packages/pluginutils/test/filterUtils.ts index 1924adab9..aa7201c06 100644 --- a/packages/pluginutils/test/filterUtils.ts +++ b/packages/pluginutils/test/filterUtils.ts @@ -90,3 +90,11 @@ test('wordRegex supports flags and escapes special characters', () => { expect(regex.test('FOO.BAR')).toBe(true); expect(regex.test('foo.barx')).toBe(false); }); + +test('wordRegex supports hyphens with the Unicode flag', () => { + const regex = wordRegex('foo-bar', 'u'); + + expect(regex.toString()).toBe('/\\bfoo-bar\\b/u'); + expect(regex.test('foo-bar')).toBe(true); + expect(regex.test('foo-barx')).toBe(false); +});