@rolldown/pluginutils
Advanced tools
| type StringOrRegExp = string | RegExp; | ||
| type PluginModuleType = 'js' | 'jsx' | 'ts' | 'tsx' | 'json' | 'text' | 'base64' | 'dataurl' | 'binary' | 'empty' | (string & {}); | ||
| export type FilterExpressionKind = FilterExpression['kind']; | ||
| export type FilterExpression = And | Or | Not | Id | ImporterId | ModuleType | Code | Query; | ||
| export type TopLevelFilterExpression = Include | Exclude; | ||
| declare class And { | ||
| kind: 'and'; | ||
| args: FilterExpression[]; | ||
| constructor(...args: FilterExpression[]); | ||
| } | ||
| declare class Or { | ||
| kind: 'or'; | ||
| args: FilterExpression[]; | ||
| constructor(...args: FilterExpression[]); | ||
| } | ||
| declare class Not { | ||
| kind: 'not'; | ||
| expr: FilterExpression; | ||
| constructor(expr: FilterExpression); | ||
| } | ||
| export interface QueryFilterObject { | ||
| [key: string]: StringOrRegExp | boolean; | ||
| } | ||
| interface IdParams { | ||
| cleanUrl?: boolean; | ||
| } | ||
| declare class Id { | ||
| kind: 'id'; | ||
| pattern: StringOrRegExp; | ||
| params: IdParams; | ||
| constructor(pattern: StringOrRegExp, params?: IdParams); | ||
| } | ||
| declare class ImporterId { | ||
| kind: 'importerId'; | ||
| pattern: StringOrRegExp; | ||
| params: IdParams; | ||
| constructor(pattern: StringOrRegExp, params?: IdParams); | ||
| } | ||
| declare class ModuleType { | ||
| kind: 'moduleType'; | ||
| pattern: PluginModuleType; | ||
| constructor(pattern: PluginModuleType); | ||
| } | ||
| declare class Code { | ||
| kind: 'code'; | ||
| pattern: StringOrRegExp; | ||
| constructor(expr: StringOrRegExp); | ||
| } | ||
| declare class Query { | ||
| kind: 'query'; | ||
| key: string; | ||
| pattern: StringOrRegExp | boolean; | ||
| constructor(key: string, pattern: StringOrRegExp | boolean); | ||
| } | ||
| declare class Include { | ||
| kind: 'include'; | ||
| expr: FilterExpression; | ||
| constructor(expr: FilterExpression); | ||
| } | ||
| declare class Exclude { | ||
| kind: 'exclude'; | ||
| expr: FilterExpression; | ||
| constructor(expr: FilterExpression); | ||
| } | ||
| export declare function and(...args: FilterExpression[]): And; | ||
| export declare function or(...args: FilterExpression[]): Or; | ||
| export declare function not(expr: FilterExpression): Not; | ||
| export declare function id(pattern: StringOrRegExp, params?: IdParams): Id; | ||
| export declare function importerId(pattern: StringOrRegExp, params?: IdParams): ImporterId; | ||
| export declare function moduleType(pattern: PluginModuleType): ModuleType; | ||
| export declare function code(pattern: StringOrRegExp): Code; | ||
| export declare function query(key: string, pattern: StringOrRegExp | boolean): Query; | ||
| export declare function include(expr: FilterExpression): Include; | ||
| export declare function exclude(expr: FilterExpression): Exclude; | ||
| /** | ||
| * convert a queryObject to FilterExpression like | ||
| * ```js | ||
| * and(query(k1, v1), query(k2, v2)) | ||
| * ``` | ||
| * @param queryFilterObject The query filter object needs to be matched. | ||
| * @returns a `And` FilterExpression | ||
| */ | ||
| export declare function queries(queryFilter: QueryFilterObject): And; | ||
| export declare function interpreter(exprs: TopLevelFilterExpression | TopLevelFilterExpression[], code?: string, id?: string, moduleType?: PluginModuleType, importerId?: string): boolean; | ||
| interface InterpreterCtx { | ||
| urlSearchParamsCache?: URLSearchParams; | ||
| } | ||
| export declare function interpreterImpl(expr: TopLevelFilterExpression[], code?: string, id?: string, moduleType?: PluginModuleType, importerId?: string, ctx?: InterpreterCtx): boolean; | ||
| export declare function exprInterpreter(expr: FilterExpression, code?: string, id?: string, moduleType?: PluginModuleType, importerId?: string, ctx?: InterpreterCtx): boolean; | ||
| export {}; |
| import { cleanUrl, extractQueryWithoutFragment } from "../utils.js"; | ||
| class And { | ||
| kind; | ||
| args; | ||
| constructor(...args) { | ||
| if (args.length === 0) { | ||
| throw new Error('`And` expects at least one operand'); | ||
| } | ||
| this.args = args; | ||
| this.kind = 'and'; | ||
| } | ||
| } | ||
| class Or { | ||
| kind; | ||
| args; | ||
| constructor(...args) { | ||
| if (args.length === 0) { | ||
| throw new Error('`Or` expects at least one operand'); | ||
| } | ||
| this.args = args; | ||
| this.kind = 'or'; | ||
| } | ||
| } | ||
| class Not { | ||
| kind; | ||
| expr; | ||
| constructor(expr) { | ||
| this.expr = expr; | ||
| this.kind = 'not'; | ||
| } | ||
| } | ||
| class Id { | ||
| kind; | ||
| pattern; | ||
| params; | ||
| constructor(pattern, params) { | ||
| this.pattern = pattern; | ||
| this.kind = 'id'; | ||
| this.params = params ?? { | ||
| cleanUrl: false, | ||
| }; | ||
| } | ||
| } | ||
| class ImporterId { | ||
| kind; | ||
| pattern; | ||
| params; | ||
| constructor(pattern, params) { | ||
| this.pattern = pattern; | ||
| this.kind = 'importerId'; | ||
| this.params = params ?? { | ||
| cleanUrl: false, | ||
| }; | ||
| } | ||
| } | ||
| class ModuleType { | ||
| kind; | ||
| pattern; | ||
| constructor(pattern) { | ||
| this.pattern = pattern; | ||
| this.kind = 'moduleType'; | ||
| } | ||
| } | ||
| class Code { | ||
| kind; | ||
| pattern; | ||
| constructor(expr) { | ||
| this.pattern = expr; | ||
| this.kind = 'code'; | ||
| } | ||
| } | ||
| class Query { | ||
| kind; | ||
| key; | ||
| pattern; | ||
| constructor(key, pattern) { | ||
| this.pattern = pattern; | ||
| this.key = key; | ||
| this.kind = 'query'; | ||
| } | ||
| } | ||
| class Include { | ||
| kind; | ||
| expr; | ||
| constructor(expr) { | ||
| this.expr = expr; | ||
| this.kind = 'include'; | ||
| } | ||
| } | ||
| class Exclude { | ||
| kind; | ||
| expr; | ||
| constructor(expr) { | ||
| this.expr = expr; | ||
| this.kind = 'exclude'; | ||
| } | ||
| } | ||
| export function and(...args) { | ||
| return new And(...args); | ||
| } | ||
| export function or(...args) { | ||
| return new Or(...args); | ||
| } | ||
| export function not(expr) { | ||
| return new Not(expr); | ||
| } | ||
| export function id(pattern, params) { | ||
| return new Id(pattern, params); | ||
| } | ||
| export function importerId(pattern, params) { | ||
| return new ImporterId(pattern, params); | ||
| } | ||
| export function moduleType(pattern) { | ||
| return new ModuleType(pattern); | ||
| } | ||
| export function code(pattern) { | ||
| return new Code(pattern); | ||
| } | ||
| /* | ||
| * There are three kinds of conditions are supported: | ||
| * 1. `boolean`: if the value is `true`, the key must exist and be truthy. if the value is `false`, the key must not exist or be falsy. | ||
| * 2. `string`: the key must exist and be equal to the value. | ||
| * 3. `RegExp`: the key must exist and match the value. | ||
| */ | ||
| export function query(key, pattern) { | ||
| return new Query(key, pattern); | ||
| } | ||
| export function include(expr) { | ||
| return new Include(expr); | ||
| } | ||
| export function exclude(expr) { | ||
| return new Exclude(expr); | ||
| } | ||
| /** | ||
| * convert a queryObject to FilterExpression like | ||
| * ```js | ||
| * and(query(k1, v1), query(k2, v2)) | ||
| * ``` | ||
| * @param queryFilterObject The query filter object needs to be matched. | ||
| * @returns a `And` FilterExpression | ||
| */ | ||
| export function queries(queryFilter) { | ||
| let arr = Object.entries(queryFilter).map(([key, value]) => { | ||
| return new Query(key, value); | ||
| }); | ||
| return and(...arr); | ||
| } | ||
| export function interpreter(exprs, code, id, moduleType, importerId) { | ||
| let arr = []; | ||
| if (Array.isArray(exprs)) { | ||
| arr = exprs; | ||
| } | ||
| else { | ||
| arr = [exprs]; | ||
| } | ||
| return interpreterImpl(arr, code, id, moduleType, importerId); | ||
| } | ||
| export function interpreterImpl(expr, code, id, moduleType, importerId, ctx = {}) { | ||
| let hasInclude = false; | ||
| for (const e of expr) { | ||
| switch (e.kind) { | ||
| case 'include': { | ||
| hasInclude = true; | ||
| if (exprInterpreter(e.expr, code, id, moduleType, importerId, ctx)) { | ||
| return true; | ||
| } | ||
| break; | ||
| } | ||
| case 'exclude': { | ||
| if (exprInterpreter(e.expr, code, id, moduleType, importerId, ctx)) { | ||
| return false; | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| return !hasInclude; | ||
| } | ||
| export function exprInterpreter(expr, code, id, moduleType, importerId, ctx = {}) { | ||
| switch (expr.kind) { | ||
| case 'and': { | ||
| return expr.args.every((e) => exprInterpreter(e, code, id, moduleType, importerId, ctx)); | ||
| } | ||
| case 'or': { | ||
| return expr.args.some((e) => exprInterpreter(e, code, id, moduleType, importerId, ctx)); | ||
| } | ||
| case 'not': { | ||
| return !exprInterpreter(expr.expr, code, id, moduleType, importerId, ctx); | ||
| } | ||
| case 'id': { | ||
| if (id === undefined) { | ||
| throw new Error('`id` is required for `id` expression'); | ||
| } | ||
| let idToMatch = id; | ||
| if (expr.params.cleanUrl) { | ||
| idToMatch = cleanUrl(idToMatch); | ||
| } | ||
| return typeof expr.pattern === 'string' | ||
| ? idToMatch === expr.pattern | ||
| : expr.pattern.test(idToMatch); | ||
| } | ||
| case 'importerId': { | ||
| if (importerId === undefined) { | ||
| return false; // Entry files have no importer, so no match | ||
| } | ||
| let importerIdToMatch = importerId; | ||
| if (expr.params.cleanUrl) { | ||
| importerIdToMatch = cleanUrl(importerIdToMatch); | ||
| } | ||
| return typeof expr.pattern === 'string' | ||
| ? importerIdToMatch === expr.pattern | ||
| : expr.pattern.test(importerIdToMatch); | ||
| } | ||
| case 'moduleType': { | ||
| if (moduleType === undefined) { | ||
| throw new Error('`moduleType` is required for `moduleType` expression'); | ||
| } | ||
| return moduleType === expr.pattern; | ||
| } | ||
| case 'code': { | ||
| if (code === undefined) { | ||
| throw new Error('`code` is required for `code` expression'); | ||
| } | ||
| return typeof expr.pattern === 'string' | ||
| ? code.includes(expr.pattern) | ||
| : expr.pattern.test(code); | ||
| } | ||
| case 'query': { | ||
| if (id === undefined) { | ||
| throw new Error('`id` is required for `Query` expression'); | ||
| } | ||
| if (!ctx.urlSearchParamsCache) { | ||
| let queryString = extractQueryWithoutFragment(id); | ||
| ctx.urlSearchParamsCache = new URLSearchParams(queryString); | ||
| } | ||
| let urlParams = ctx.urlSearchParamsCache; | ||
| if (typeof expr.pattern === 'boolean') { | ||
| if (expr.pattern) { | ||
| return urlParams.has(expr.key); | ||
| } | ||
| else { | ||
| return !urlParams.has(expr.key); | ||
| } | ||
| } | ||
| else if (typeof expr.pattern === 'string') { | ||
| return urlParams.get(expr.key) === expr.pattern; | ||
| } | ||
| else { | ||
| return expr.pattern.test(urlParams.get(expr.key) ?? ''); | ||
| } | ||
| } | ||
| default: { | ||
| throw new Error(`Expression ${JSON.stringify(expr)} is not expected.`); | ||
| } | ||
| } | ||
| } |
| /** | ||
| * Filters out Vite plugins that have `apply: 'serve'` set. | ||
| * | ||
| * Since Rolldown operates in build mode, plugins marked with `apply: 'serve'` | ||
| * are intended only for Vite's dev server and should be excluded from the build process. | ||
| * | ||
| * @param plugins - Array of plugins (can include nested arrays) | ||
| * @returns Filtered array with serve-only plugins removed | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { defineConfig } from 'rolldown'; | ||
| * import { filterVitePlugins } from '@rolldown/pluginutils'; | ||
| * import viteReact from '@vitejs/plugin-react'; | ||
| * | ||
| * export default defineConfig({ | ||
| * plugins: filterVitePlugins([ | ||
| * viteReact(), | ||
| * { | ||
| * name: 'dev-only', | ||
| * apply: 'serve', // This will be filtered out | ||
| * // ... | ||
| * } | ||
| * ]) | ||
| * }); | ||
| * ``` | ||
| */ | ||
| export declare function filterVitePlugins<T = any>(plugins: T | T[] | null | undefined | false): T[]; |
| /** | ||
| * Filters out Vite plugins that have `apply: 'serve'` set. | ||
| * | ||
| * Since Rolldown operates in build mode, plugins marked with `apply: 'serve'` | ||
| * are intended only for Vite's dev server and should be excluded from the build process. | ||
| * | ||
| * @param plugins - Array of plugins (can include nested arrays) | ||
| * @returns Filtered array with serve-only plugins removed | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { defineConfig } from 'rolldown'; | ||
| * import { filterVitePlugins } from '@rolldown/pluginutils'; | ||
| * import viteReact from '@vitejs/plugin-react'; | ||
| * | ||
| * export default defineConfig({ | ||
| * plugins: filterVitePlugins([ | ||
| * viteReact(), | ||
| * { | ||
| * name: 'dev-only', | ||
| * apply: 'serve', // This will be filtered out | ||
| * // ... | ||
| * } | ||
| * ]) | ||
| * }); | ||
| * ``` | ||
| */ | ||
| export function filterVitePlugins(plugins) { | ||
| if (!plugins) { | ||
| return []; | ||
| } | ||
| const pluginArray = Array.isArray(plugins) ? plugins : [plugins]; | ||
| const result = []; | ||
| for (const plugin of pluginArray) { | ||
| // Skip falsy values | ||
| if (!plugin) { | ||
| continue; | ||
| } | ||
| // Handle nested arrays recursively | ||
| if (Array.isArray(plugin)) { | ||
| result.push(...filterVitePlugins(plugin)); | ||
| continue; | ||
| } | ||
| // Check if plugin has apply property | ||
| const pluginWithApply = plugin; | ||
| if ('apply' in pluginWithApply) { | ||
| const applyValue = pluginWithApply.apply; | ||
| // If apply is a function, call it with build mode | ||
| if (typeof applyValue === 'function') { | ||
| try { | ||
| const shouldApply = applyValue({}, // config object | ||
| { command: 'build', mode: 'production' }); | ||
| if (shouldApply) { | ||
| result.push(plugin); | ||
| } | ||
| } | ||
| catch { | ||
| // If function throws, include the plugin to be safe | ||
| result.push(plugin); | ||
| } | ||
| } // If apply is 'serve', skip this plugin | ||
| else if (applyValue === 'serve') { | ||
| continue; | ||
| } // If apply is 'build' or anything else, include it | ||
| else { | ||
| result.push(plugin); | ||
| } | ||
| } | ||
| else { | ||
| // No apply property, include the plugin | ||
| result.push(plugin); | ||
| } | ||
| } | ||
| return result; | ||
| } |
| export * from './composable-filters.ts'; | ||
| export * from './filter-vite-plugins.ts'; | ||
| export * from './simple-filters.ts'; |
| export * from "./composable-filters.js"; | ||
| export * from "./filter-vite-plugins.js"; | ||
| export * from "./simple-filters.js"; |
| /** | ||
| * Constructs a RegExp that matches the exact string specified. | ||
| * | ||
| * This is useful for plugin hook filters. | ||
| * | ||
| * @param str the string to match. | ||
| * @param flags flags for the RegExp. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { exactRegex } from '@rolldown/pluginutils'; | ||
| * const plugin = { | ||
| * name: 'plugin', | ||
| * resolveId: { | ||
| * filter: { id: exactRegex('foo') }, | ||
| * handler(id) {} // will only be called for `foo` | ||
| * } | ||
| * } | ||
| * ``` | ||
| */ | ||
| export declare function exactRegex(str: string, flags?: string): RegExp; | ||
| /** | ||
| * Constructs a RegExp that matches a value that has the specified prefix. | ||
| * | ||
| * This is useful for plugin hook filters. | ||
| * | ||
| * @param str the string to match. | ||
| * @param flags flags for the RegExp. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { prefixRegex } from '@rolldown/pluginutils'; | ||
| * const plugin = { | ||
| * name: 'plugin', | ||
| * resolveId: { | ||
| * filter: { id: prefixRegex('foo') }, | ||
| * handler(id) {} // will only be called for IDs starting with `foo` | ||
| * } | ||
| * } | ||
| * ``` | ||
| */ | ||
| export declare function prefixRegex(str: string, flags?: string): RegExp; | ||
| type WidenString<T> = T extends string ? string : T; | ||
| /** | ||
| * Converts a id filter to match with an id with a query. | ||
| * | ||
| * @param input the id filters to convert. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { makeIdFiltersToMatchWithQuery } from '@rolldown/pluginutils'; | ||
| * const plugin = { | ||
| * name: 'plugin', | ||
| * transform: { | ||
| * filter: { id: makeIdFiltersToMatchWithQuery(['**' + '/*.js', /\.ts$/]) }, | ||
| * // The handler will be called for IDs like: | ||
| * // - foo.js | ||
| * // - foo.js?foo | ||
| * // - foo.txt?foo.js | ||
| * // - foo.ts | ||
| * // - foo.ts?foo | ||
| * // - foo.txt?foo.ts | ||
| * handler(code, id) {} | ||
| * } | ||
| * } | ||
| * ``` | ||
| */ | ||
| export declare function makeIdFiltersToMatchWithQuery<T extends string | RegExp>(input: T): WidenString<T>; | ||
| export declare function makeIdFiltersToMatchWithQuery<T extends string | RegExp>(input: readonly T[]): WidenString<T>[]; | ||
| export declare function makeIdFiltersToMatchWithQuery(input: string | RegExp | readonly (string | RegExp)[]): string | RegExp | (string | RegExp)[]; | ||
| export {}; |
| /** | ||
| * Constructs a RegExp that matches the exact string specified. | ||
| * | ||
| * This is useful for plugin hook filters. | ||
| * | ||
| * @param str the string to match. | ||
| * @param flags flags for the RegExp. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { exactRegex } from '@rolldown/pluginutils'; | ||
| * const plugin = { | ||
| * name: 'plugin', | ||
| * resolveId: { | ||
| * filter: { id: exactRegex('foo') }, | ||
| * handler(id) {} // will only be called for `foo` | ||
| * } | ||
| * } | ||
| * ``` | ||
| */ | ||
| export function exactRegex(str, flags) { | ||
| return new RegExp(`^${escapeRegex(str)}$`, flags); | ||
| } | ||
| /** | ||
| * Constructs a RegExp that matches a value that has the specified prefix. | ||
| * | ||
| * This is useful for plugin hook filters. | ||
| * | ||
| * @param str the string to match. | ||
| * @param flags flags for the RegExp. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { prefixRegex } from '@rolldown/pluginutils'; | ||
| * const plugin = { | ||
| * name: 'plugin', | ||
| * resolveId: { | ||
| * filter: { id: prefixRegex('foo') }, | ||
| * handler(id) {} // will only be called for IDs starting with `foo` | ||
| * } | ||
| * } | ||
| * ``` | ||
| */ | ||
| export function prefixRegex(str, flags) { | ||
| return new RegExp(`^${escapeRegex(str)}`, flags); | ||
| } | ||
| const escapeRegexRE = /[-/\\^$*+?.()|[\]{}]/g; | ||
| function escapeRegex(str) { | ||
| return str.replace(escapeRegexRE, '\\$&'); | ||
| } | ||
| export function makeIdFiltersToMatchWithQuery(input) { | ||
| if (!Array.isArray(input)) { | ||
| return makeIdFilterToMatchWithQuery( | ||
| // Array.isArray cannot narrow the type | ||
| // https://github.com/microsoft/TypeScript/issues/17002 | ||
| input); | ||
| } | ||
| return input.map((i) => makeIdFilterToMatchWithQuery(i)); | ||
| } | ||
| function makeIdFilterToMatchWithQuery(input) { | ||
| if (typeof input === 'string') { | ||
| return `${input}{?*,}`; | ||
| } | ||
| return makeRegexIdFilterToMatchWithQuery(input); | ||
| } | ||
| function makeRegexIdFilterToMatchWithQuery(input) { | ||
| return new RegExp( | ||
| // replace `$` with `(?:\?.*)?$` (ignore `\$`) | ||
| input.source.replace(/(?<!\\)\$/g, '(?:\\?.*)?$'), input.flags); | ||
| } |
| export declare function cleanUrl(url: string): string; | ||
| export declare function extractQueryWithoutFragment(url: string): string; |
| const postfixRE = /[?#].*$/; | ||
| export function cleanUrl(url) { | ||
| return url.replace(postfixRE, ''); | ||
| } | ||
| export function extractQueryWithoutFragment(url) { | ||
| const questionMarkIndex = url.indexOf('?'); | ||
| if (questionMarkIndex === -1) { | ||
| return ''; | ||
| } | ||
| const fragmentIndex = url.indexOf('#', questionMarkIndex); // Search for # after ? | ||
| if (fragmentIndex === -1) { | ||
| return url.substring(questionMarkIndex); | ||
| } | ||
| else { | ||
| return url.substring(questionMarkIndex, fragmentIndex); | ||
| } | ||
| } |
+77
| # @rolldown/pluginutils | ||
| A utility library for building flexible, composable filter expressions that can be used in plugin hook filters of Rolldown/Vite/Rollup/Unplugin plugins. | ||
| ## Installation | ||
| ```sh | ||
| pnpm add @rolldown/pluginutils | ||
| ``` | ||
| ## Usage | ||
| ### Simple Filters | ||
| ```ts | ||
| import { exactRegex, makeIdFiltersToMatchWithQuery, prefixRegex } from '@rolldown/pluginutils'; | ||
| // Match exactly 'foo.js' | ||
| const filter = exactRegex('foo.js'); | ||
| // Match any id starting with 'lib/' | ||
| const prefix = prefixRegex('lib/'); | ||
| // Match ids with query params (e.g. 'foo.js?bar') | ||
| const idFilters = makeIdFiltersToMatchWithQuery(['**/*.js', /\.ts$/]); | ||
| // Usage in a plugin to define a hook filter | ||
| const myPlugin = { | ||
| resolveId: { | ||
| filter: { | ||
| id: [exactRegex('MY_ID_TO_CHECK'), /some-other-regex/], | ||
| }, | ||
| handler(id) { | ||
| // Your code here | ||
| }, | ||
| }, | ||
| }; | ||
| ``` | ||
| ### Composable Filters | ||
| > [!WARNING] Composable filters are not yet supported in Vite, Rolldown-Vite or unplugin. They can be used in Rolldown plugins only. | ||
| ```ts | ||
| import { and, id, include, moduleType, query } from '@rolldown/pluginutils'; | ||
| // Build a filter expression | ||
| const filterExpr = and(id(/\.ts$/), moduleType('ts'), query('foo', true)); | ||
| // Usage in a plugin to define a hook filter | ||
| const myPlugin = { | ||
| transform: { | ||
| filter: [include(filterExpr)], | ||
| handler(code, id, options) { | ||
| // Your code here | ||
| }, | ||
| }, | ||
| }; | ||
| ``` | ||
| ## API Reference | ||
| ### Simple Filters | ||
| - `exactRegex(str: string, flags?: string): RegExp` — Matches the exact string. | ||
| - `prefixRegex(str: string, flags?: string): RegExp` — Matches values with the given prefix. | ||
| - `makeIdFiltersToMatchWithQuery(input: string | RegExp | (string | RegExp)[]): string | RegExp | (string | RegExp)[]` — Adapts filters to match ids with query params. | ||
| ### Composable Filters | ||
| - `and(...exprs)` / `or(...exprs)` / `not(expr)` — Logical composition of filter expressions. | ||
| - `id(pattern, params?)` — Filter by id (string or RegExp). | ||
| - `moduleType(type)` — Filter by module type (e.g. 'js', 'tsx', or 'json'). | ||
| - `code(pattern)` — Filter by code content. | ||
| - `query(key, pattern)` — Filter by query parameter. | ||
| - `include(expr)` / `exclude(expr)` — Top-level include/exclude wrappers. | ||
| - `queries(obj)` — Compose multiple query filters. |
+1
-116
@@ -1,116 +0,1 @@ | ||
| //#region src/composable-filters.d.ts | ||
| type StringOrRegExp = string | RegExp; | ||
| type PluginModuleType = "js" | "jsx" | "ts" | "tsx" | "json" | "text" | "base64" | "dataurl" | "binary" | "empty" | (string & {}); | ||
| type FilterExpressionKind = FilterExpression["kind"]; | ||
| type FilterExpression = And | Or | Not | Id | ModuleType | Code | Query; | ||
| type TopLevelFilterExpression = Include | Exclude; | ||
| declare class And { | ||
| kind: "and"; | ||
| args: FilterExpression[]; | ||
| constructor(...args: FilterExpression[]); | ||
| } | ||
| declare class Or { | ||
| kind: "or"; | ||
| args: FilterExpression[]; | ||
| constructor(...args: FilterExpression[]); | ||
| } | ||
| declare class Not { | ||
| kind: "not"; | ||
| expr: FilterExpression; | ||
| constructor(expr: FilterExpression); | ||
| } | ||
| interface QueryFilterObject { | ||
| [key: string]: StringOrRegExp | boolean; | ||
| } | ||
| interface IdParams { | ||
| cleanUrl?: boolean; | ||
| } | ||
| declare class Id { | ||
| kind: "id"; | ||
| pattern: StringOrRegExp; | ||
| params: IdParams; | ||
| constructor(pattern: StringOrRegExp, params?: IdParams); | ||
| } | ||
| declare class ModuleType { | ||
| kind: "moduleType"; | ||
| pattern: PluginModuleType; | ||
| constructor(pattern: PluginModuleType); | ||
| } | ||
| declare class Code { | ||
| kind: "code"; | ||
| pattern: StringOrRegExp; | ||
| constructor(expr: StringOrRegExp); | ||
| } | ||
| declare class Query { | ||
| kind: "query"; | ||
| key: string; | ||
| pattern: StringOrRegExp | boolean; | ||
| constructor(key: string, pattern: StringOrRegExp | boolean); | ||
| } | ||
| declare class Include { | ||
| kind: "include"; | ||
| expr: FilterExpression; | ||
| constructor(expr: FilterExpression); | ||
| } | ||
| declare class Exclude { | ||
| kind: "exclude"; | ||
| expr: FilterExpression; | ||
| constructor(expr: FilterExpression); | ||
| } | ||
| declare function and(...args: FilterExpression[]): And; | ||
| declare function or(...args: FilterExpression[]): Or; | ||
| declare function not(expr: FilterExpression): Not; | ||
| declare function id(pattern: StringOrRegExp, params?: IdParams): Id; | ||
| declare function moduleType(pattern: PluginModuleType): ModuleType; | ||
| declare function code(pattern: StringOrRegExp): Code; | ||
| declare function query(key: string, pattern: StringOrRegExp | boolean): Query; | ||
| declare function include(expr: FilterExpression): Include; | ||
| declare function exclude(expr: FilterExpression): Exclude; | ||
| /** | ||
| * convert a queryObject to FilterExpression like | ||
| * ```js | ||
| * and(query(k1, v1), query(k2, v2)) | ||
| * ``` | ||
| * @param queryFilterObject The query filter object needs to be matched. | ||
| * @returns a `And` FilterExpression | ||
| */ | ||
| declare function queries(queryFilter: QueryFilterObject): And; | ||
| declare function interpreter(exprs: TopLevelFilterExpression | TopLevelFilterExpression[], code?: string, id?: string, moduleType?: PluginModuleType): boolean; | ||
| interface InterpreterCtx { | ||
| urlSearchParamsCache?: URLSearchParams; | ||
| } | ||
| declare function interpreterImpl(expr: TopLevelFilterExpression[], code?: string, id?: string, moduleType?: PluginModuleType, ctx?: InterpreterCtx): boolean; | ||
| declare function exprInterpreter(expr: FilterExpression, code?: string, id?: string, moduleType?: PluginModuleType, ctx?: InterpreterCtx): boolean; | ||
| //#endregion | ||
| //#region src/simple-filters.d.ts | ||
| /** | ||
| * Constructs a RegExp that matches the exact string specified. | ||
| * | ||
| * This is useful for plugin hook filters. | ||
| * | ||
| * @param str the string to match. | ||
| * @param flags flags for the RegExp. | ||
| */ | ||
| declare function exactRegex(str: string, flags?: string): RegExp; | ||
| /** | ||
| * Constructs a RegExp that matches a value that has the specified prefix. | ||
| * | ||
| * This is useful for plugin hook filters. | ||
| * | ||
| * @param str the string to match. | ||
| * @param flags flags for the RegExp. | ||
| */ | ||
| declare function prefixRegex(str: string, flags?: string): RegExp; | ||
| type WidenString<T> = T extends string ? string : T; | ||
| /** | ||
| * Converts a id filter to match with an id with a query. | ||
| * | ||
| * @param input the id filters to convert. | ||
| */ | ||
| declare function makeIdFiltersToMatchWithQuery<T extends string | RegExp>(input: T): WidenString<T>; | ||
| declare function makeIdFiltersToMatchWithQuery<T extends string | RegExp>(input: readonly T[]): WidenString<T>[]; | ||
| declare function makeIdFiltersToMatchWithQuery(input: string | RegExp | readonly (string | RegExp)[]): string | RegExp | (string | RegExp)[]; | ||
| //#endregion | ||
| export { FilterExpression, FilterExpressionKind, QueryFilterObject, TopLevelFilterExpression, and, code, exactRegex, exclude, exprInterpreter, id, include, interpreter, interpreterImpl, makeIdFiltersToMatchWithQuery, moduleType, not, or, prefixRegex, queries, query }; | ||
| export * from './filter/index.ts'; |
+1
-239
@@ -1,239 +0,1 @@ | ||
| //#region src/utils.ts | ||
| const postfixRE = /[?#].*$/; | ||
| function cleanUrl(url) { | ||
| return url.replace(postfixRE, ""); | ||
| } | ||
| function extractQueryWithoutFragment(url) { | ||
| const questionMarkIndex = url.indexOf("?"); | ||
| if (questionMarkIndex === -1) return ""; | ||
| const fragmentIndex = url.indexOf("#", questionMarkIndex); | ||
| if (fragmentIndex === -1) return url.substring(questionMarkIndex); | ||
| else return url.substring(questionMarkIndex, fragmentIndex); | ||
| } | ||
| //#endregion | ||
| //#region src/composable-filters.ts | ||
| var And = class { | ||
| kind; | ||
| args; | ||
| constructor(...args) { | ||
| if (args.length === 0) throw new Error("`And` expects at least one operand"); | ||
| this.args = args; | ||
| this.kind = "and"; | ||
| } | ||
| }; | ||
| var Or = class { | ||
| kind; | ||
| args; | ||
| constructor(...args) { | ||
| if (args.length === 0) throw new Error("`Or` expects at least one operand"); | ||
| this.args = args; | ||
| this.kind = "or"; | ||
| } | ||
| }; | ||
| var Not = class { | ||
| kind; | ||
| expr; | ||
| constructor(expr) { | ||
| this.expr = expr; | ||
| this.kind = "not"; | ||
| } | ||
| }; | ||
| var Id = class { | ||
| kind; | ||
| pattern; | ||
| params; | ||
| constructor(pattern, params) { | ||
| this.pattern = pattern; | ||
| this.kind = "id"; | ||
| this.params = params ?? { cleanUrl: false }; | ||
| } | ||
| }; | ||
| var ModuleType = class { | ||
| kind; | ||
| pattern; | ||
| constructor(pattern) { | ||
| this.pattern = pattern; | ||
| this.kind = "moduleType"; | ||
| } | ||
| }; | ||
| var Code = class { | ||
| kind; | ||
| pattern; | ||
| constructor(expr) { | ||
| this.pattern = expr; | ||
| this.kind = "code"; | ||
| } | ||
| }; | ||
| var Query = class { | ||
| kind; | ||
| key; | ||
| pattern; | ||
| constructor(key, pattern) { | ||
| this.pattern = pattern; | ||
| this.key = key; | ||
| this.kind = "query"; | ||
| } | ||
| }; | ||
| var Include = class { | ||
| kind; | ||
| expr; | ||
| constructor(expr) { | ||
| this.expr = expr; | ||
| this.kind = "include"; | ||
| } | ||
| }; | ||
| var Exclude = class { | ||
| kind; | ||
| expr; | ||
| constructor(expr) { | ||
| this.expr = expr; | ||
| this.kind = "exclude"; | ||
| } | ||
| }; | ||
| function and(...args) { | ||
| return new And(...args); | ||
| } | ||
| function or(...args) { | ||
| return new Or(...args); | ||
| } | ||
| function not(expr) { | ||
| return new Not(expr); | ||
| } | ||
| function id(pattern, params) { | ||
| return new Id(pattern, params); | ||
| } | ||
| function moduleType(pattern) { | ||
| return new ModuleType(pattern); | ||
| } | ||
| function code(pattern) { | ||
| return new Code(pattern); | ||
| } | ||
| function query(key, pattern) { | ||
| return new Query(key, pattern); | ||
| } | ||
| function include(expr) { | ||
| return new Include(expr); | ||
| } | ||
| function exclude(expr) { | ||
| return new Exclude(expr); | ||
| } | ||
| /** | ||
| * convert a queryObject to FilterExpression like | ||
| * ```js | ||
| * and(query(k1, v1), query(k2, v2)) | ||
| * ``` | ||
| * @param queryFilterObject The query filter object needs to be matched. | ||
| * @returns a `And` FilterExpression | ||
| */ | ||
| function queries(queryFilter) { | ||
| let arr = Object.entries(queryFilter).map(([key, value]) => { | ||
| return new Query(key, value); | ||
| }); | ||
| return and(...arr); | ||
| } | ||
| function interpreter(exprs, code$1, id$1, moduleType$1) { | ||
| let arr = []; | ||
| if (Array.isArray(exprs)) arr = exprs; | ||
| else arr = [exprs]; | ||
| return interpreterImpl(arr, code$1, id$1, moduleType$1); | ||
| } | ||
| function interpreterImpl(expr, code$1, id$1, moduleType$1, ctx = {}) { | ||
| let hasInclude = false; | ||
| for (const e of expr) switch (e.kind) { | ||
| case "include": { | ||
| hasInclude = true; | ||
| if (exprInterpreter(e.expr, code$1, id$1, moduleType$1, ctx)) return true; | ||
| break; | ||
| } | ||
| case "exclude": { | ||
| if (exprInterpreter(e.expr, code$1, id$1, moduleType$1)) return false; | ||
| break; | ||
| } | ||
| } | ||
| return !hasInclude; | ||
| } | ||
| function exprInterpreter(expr, code$1, id$1, moduleType$1, ctx = {}) { | ||
| switch (expr.kind) { | ||
| case "and": return expr.args.every((e) => exprInterpreter(e, code$1, id$1, moduleType$1, ctx)); | ||
| case "or": return expr.args.some((e) => exprInterpreter(e, code$1, id$1, moduleType$1, ctx)); | ||
| case "not": return !exprInterpreter(expr.expr, code$1, id$1, moduleType$1, ctx); | ||
| case "id": { | ||
| if (id$1 === void 0) throw new Error("`id` is required for `id` expression"); | ||
| if (expr.params.cleanUrl) id$1 = cleanUrl(id$1); | ||
| return typeof expr.pattern === "string" ? id$1 === expr.pattern : expr.pattern.test(id$1); | ||
| } | ||
| case "moduleType": { | ||
| if (moduleType$1 === void 0) throw new Error("`moduleType` is required for `moduleType` expression"); | ||
| return moduleType$1 === expr.pattern; | ||
| } | ||
| case "code": { | ||
| if (code$1 === void 0) throw new Error("`code` is required for `code` expression"); | ||
| return typeof expr.pattern === "string" ? code$1.includes(expr.pattern) : expr.pattern.test(code$1); | ||
| } | ||
| case "query": { | ||
| if (id$1 === void 0) throw new Error("`id` is required for `Query` expression"); | ||
| if (!ctx.urlSearchParamsCache) { | ||
| let queryString = extractQueryWithoutFragment(id$1); | ||
| ctx.urlSearchParamsCache = new URLSearchParams(queryString); | ||
| } | ||
| let urlParams = ctx.urlSearchParamsCache; | ||
| if (typeof expr.pattern === "boolean") if (expr.pattern) return urlParams.has(expr.key); | ||
| else return !urlParams.has(expr.key); | ||
| else if (typeof expr.pattern === "string") return urlParams.get(expr.key) === expr.pattern; | ||
| else return expr.pattern.test(urlParams.get(expr.key) ?? ""); | ||
| } | ||
| default: throw new Error(`Expression ${JSON.stringify(expr)} is not expected.`); | ||
| } | ||
| } | ||
| //#endregion | ||
| //#region src/simple-filters.ts | ||
| /** | ||
| * Constructs a RegExp that matches the exact string specified. | ||
| * | ||
| * This is useful for plugin hook filters. | ||
| * | ||
| * @param str the string to match. | ||
| * @param flags flags for the RegExp. | ||
| */ | ||
| function exactRegex(str, flags) { | ||
| return new RegExp(`^${escapeRegex(str)}$`, flags); | ||
| } | ||
| /** | ||
| * Constructs a RegExp that matches a value that has the specified prefix. | ||
| * | ||
| * This is useful for plugin hook filters. | ||
| * | ||
| * @param str the string to match. | ||
| * @param flags flags for the RegExp. | ||
| */ | ||
| function prefixRegex(str, flags) { | ||
| return new RegExp(`^${escapeRegex(str)}`, flags); | ||
| } | ||
| const escapeRegexRE = /[-/\\^$*+?.()|[\]{}]/g; | ||
| function escapeRegex(str) { | ||
| return str.replace(escapeRegexRE, "\\$&"); | ||
| } | ||
| function makeIdFiltersToMatchWithQuery(input) { | ||
| if (!Array.isArray(input)) return makeIdFilterToMatchWithQuery( | ||
| // Array.isArray cannot narrow the type | ||
| // https://github.com/microsoft/TypeScript/issues/17002 | ||
| input | ||
| ); | ||
| return input.map((i) => makeIdFilterToMatchWithQuery(i)); | ||
| } | ||
| function makeIdFilterToMatchWithQuery(input) { | ||
| if (typeof input === "string") return `${input}{?*,}`; | ||
| return makeRegexIdFilterToMatchWithQuery(input); | ||
| } | ||
| function makeRegexIdFilterToMatchWithQuery(input) { | ||
| return new RegExp( | ||
| // replace `$` with `(?:\?.*)?$` (ignore `\$`) | ||
| input.source.replace(/(?<!\\)\$/g, "(?:\\?.*)?$"), | ||
| input.flags | ||
| ); | ||
| } | ||
| //#endregion | ||
| export { and, code, exactRegex, exclude, exprInterpreter, id, include, interpreter, interpreterImpl, makeIdFiltersToMatchWithQuery, moduleType, not, or, prefixRegex, queries, query }; | ||
| export * from "./filter/index.js"; |
+18
-17
| { | ||
| "name": "@rolldown/pluginutils", | ||
| "version": "1.0.0-beta.9-commit.d91dfb5", | ||
| "version": "1.0.0-rc.1", | ||
| "homepage": "https://rolldown.rs/", | ||
| "license": "MIT", | ||
| "type": "module", | ||
| "repository": { | ||
@@ -11,27 +11,28 @@ "type": "git", | ||
| }, | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "main": "./dist/index.cjs", | ||
| "files": [ | ||
| "dist" | ||
| ], | ||
| "type": "module", | ||
| "main": "./dist/index.js", | ||
| "module": "./dist/index.js", | ||
| "types": "./dist/index.d.ts", | ||
| "exports": { | ||
| ".": { | ||
| "import": "./dist/index.js", | ||
| "require": "./dist/index.cjs" | ||
| } | ||
| ".": "./dist/index.js", | ||
| "./filter": "./dist/filter/index.js", | ||
| "./package.json": "./package.json" | ||
| }, | ||
| "files": [ | ||
| "dist" | ||
| ], | ||
| "publishConfig": { | ||
| "access": "public" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/picomatch": "^4.0.0", | ||
| "picomatch": "^4.0.2", | ||
| "tsdown": "0.11.11", | ||
| "vitest": "^3.0.1" | ||
| "typescript": "^5.8.3", | ||
| "vitest": "^4.0.15" | ||
| }, | ||
| "scripts": { | ||
| "build": "tsdown", | ||
| "test": "vitest --typecheck" | ||
| "build": "tsc", | ||
| "test": "vitest --typecheck", | ||
| "publint": "publint ." | ||
| } | ||
| } |
-256
| "use strict"; | ||
| //#region src/utils.ts | ||
| const postfixRE = /[?#].*$/; | ||
| function cleanUrl(url) { | ||
| return url.replace(postfixRE, ""); | ||
| } | ||
| function extractQueryWithoutFragment(url) { | ||
| const questionMarkIndex = url.indexOf("?"); | ||
| if (questionMarkIndex === -1) return ""; | ||
| const fragmentIndex = url.indexOf("#", questionMarkIndex); | ||
| if (fragmentIndex === -1) return url.substring(questionMarkIndex); | ||
| else return url.substring(questionMarkIndex, fragmentIndex); | ||
| } | ||
| //#endregion | ||
| //#region src/composable-filters.ts | ||
| var And = class { | ||
| kind; | ||
| args; | ||
| constructor(...args) { | ||
| if (args.length === 0) throw new Error("`And` expects at least one operand"); | ||
| this.args = args; | ||
| this.kind = "and"; | ||
| } | ||
| }; | ||
| var Or = class { | ||
| kind; | ||
| args; | ||
| constructor(...args) { | ||
| if (args.length === 0) throw new Error("`Or` expects at least one operand"); | ||
| this.args = args; | ||
| this.kind = "or"; | ||
| } | ||
| }; | ||
| var Not = class { | ||
| kind; | ||
| expr; | ||
| constructor(expr) { | ||
| this.expr = expr; | ||
| this.kind = "not"; | ||
| } | ||
| }; | ||
| var Id = class { | ||
| kind; | ||
| pattern; | ||
| params; | ||
| constructor(pattern, params) { | ||
| this.pattern = pattern; | ||
| this.kind = "id"; | ||
| this.params = params ?? { cleanUrl: false }; | ||
| } | ||
| }; | ||
| var ModuleType = class { | ||
| kind; | ||
| pattern; | ||
| constructor(pattern) { | ||
| this.pattern = pattern; | ||
| this.kind = "moduleType"; | ||
| } | ||
| }; | ||
| var Code = class { | ||
| kind; | ||
| pattern; | ||
| constructor(expr) { | ||
| this.pattern = expr; | ||
| this.kind = "code"; | ||
| } | ||
| }; | ||
| var Query = class { | ||
| kind; | ||
| key; | ||
| pattern; | ||
| constructor(key, pattern) { | ||
| this.pattern = pattern; | ||
| this.key = key; | ||
| this.kind = "query"; | ||
| } | ||
| }; | ||
| var Include = class { | ||
| kind; | ||
| expr; | ||
| constructor(expr) { | ||
| this.expr = expr; | ||
| this.kind = "include"; | ||
| } | ||
| }; | ||
| var Exclude = class { | ||
| kind; | ||
| expr; | ||
| constructor(expr) { | ||
| this.expr = expr; | ||
| this.kind = "exclude"; | ||
| } | ||
| }; | ||
| function and(...args) { | ||
| return new And(...args); | ||
| } | ||
| function or(...args) { | ||
| return new Or(...args); | ||
| } | ||
| function not(expr) { | ||
| return new Not(expr); | ||
| } | ||
| function id(pattern, params) { | ||
| return new Id(pattern, params); | ||
| } | ||
| function moduleType(pattern) { | ||
| return new ModuleType(pattern); | ||
| } | ||
| function code(pattern) { | ||
| return new Code(pattern); | ||
| } | ||
| function query(key, pattern) { | ||
| return new Query(key, pattern); | ||
| } | ||
| function include(expr) { | ||
| return new Include(expr); | ||
| } | ||
| function exclude(expr) { | ||
| return new Exclude(expr); | ||
| } | ||
| /** | ||
| * convert a queryObject to FilterExpression like | ||
| * ```js | ||
| * and(query(k1, v1), query(k2, v2)) | ||
| * ``` | ||
| * @param queryFilterObject The query filter object needs to be matched. | ||
| * @returns a `And` FilterExpression | ||
| */ | ||
| function queries(queryFilter) { | ||
| let arr = Object.entries(queryFilter).map(([key, value]) => { | ||
| return new Query(key, value); | ||
| }); | ||
| return and(...arr); | ||
| } | ||
| function interpreter(exprs, code$1, id$1, moduleType$1) { | ||
| let arr = []; | ||
| if (Array.isArray(exprs)) arr = exprs; | ||
| else arr = [exprs]; | ||
| return interpreterImpl(arr, code$1, id$1, moduleType$1); | ||
| } | ||
| function interpreterImpl(expr, code$1, id$1, moduleType$1, ctx = {}) { | ||
| let hasInclude = false; | ||
| for (const e of expr) switch (e.kind) { | ||
| case "include": { | ||
| hasInclude = true; | ||
| if (exprInterpreter(e.expr, code$1, id$1, moduleType$1, ctx)) return true; | ||
| break; | ||
| } | ||
| case "exclude": { | ||
| if (exprInterpreter(e.expr, code$1, id$1, moduleType$1)) return false; | ||
| break; | ||
| } | ||
| } | ||
| return !hasInclude; | ||
| } | ||
| function exprInterpreter(expr, code$1, id$1, moduleType$1, ctx = {}) { | ||
| switch (expr.kind) { | ||
| case "and": return expr.args.every((e) => exprInterpreter(e, code$1, id$1, moduleType$1, ctx)); | ||
| case "or": return expr.args.some((e) => exprInterpreter(e, code$1, id$1, moduleType$1, ctx)); | ||
| case "not": return !exprInterpreter(expr.expr, code$1, id$1, moduleType$1, ctx); | ||
| case "id": { | ||
| if (id$1 === void 0) throw new Error("`id` is required for `id` expression"); | ||
| if (expr.params.cleanUrl) id$1 = cleanUrl(id$1); | ||
| return typeof expr.pattern === "string" ? id$1 === expr.pattern : expr.pattern.test(id$1); | ||
| } | ||
| case "moduleType": { | ||
| if (moduleType$1 === void 0) throw new Error("`moduleType` is required for `moduleType` expression"); | ||
| return moduleType$1 === expr.pattern; | ||
| } | ||
| case "code": { | ||
| if (code$1 === void 0) throw new Error("`code` is required for `code` expression"); | ||
| return typeof expr.pattern === "string" ? code$1.includes(expr.pattern) : expr.pattern.test(code$1); | ||
| } | ||
| case "query": { | ||
| if (id$1 === void 0) throw new Error("`id` is required for `Query` expression"); | ||
| if (!ctx.urlSearchParamsCache) { | ||
| let queryString = extractQueryWithoutFragment(id$1); | ||
| ctx.urlSearchParamsCache = new URLSearchParams(queryString); | ||
| } | ||
| let urlParams = ctx.urlSearchParamsCache; | ||
| if (typeof expr.pattern === "boolean") if (expr.pattern) return urlParams.has(expr.key); | ||
| else return !urlParams.has(expr.key); | ||
| else if (typeof expr.pattern === "string") return urlParams.get(expr.key) === expr.pattern; | ||
| else return expr.pattern.test(urlParams.get(expr.key) ?? ""); | ||
| } | ||
| default: throw new Error(`Expression ${JSON.stringify(expr)} is not expected.`); | ||
| } | ||
| } | ||
| //#endregion | ||
| //#region src/simple-filters.ts | ||
| /** | ||
| * Constructs a RegExp that matches the exact string specified. | ||
| * | ||
| * This is useful for plugin hook filters. | ||
| * | ||
| * @param str the string to match. | ||
| * @param flags flags for the RegExp. | ||
| */ | ||
| function exactRegex(str, flags) { | ||
| return new RegExp(`^${escapeRegex(str)}$`, flags); | ||
| } | ||
| /** | ||
| * Constructs a RegExp that matches a value that has the specified prefix. | ||
| * | ||
| * This is useful for plugin hook filters. | ||
| * | ||
| * @param str the string to match. | ||
| * @param flags flags for the RegExp. | ||
| */ | ||
| function prefixRegex(str, flags) { | ||
| return new RegExp(`^${escapeRegex(str)}`, flags); | ||
| } | ||
| const escapeRegexRE = /[-/\\^$*+?.()|[\]{}]/g; | ||
| function escapeRegex(str) { | ||
| return str.replace(escapeRegexRE, "\\$&"); | ||
| } | ||
| function makeIdFiltersToMatchWithQuery(input) { | ||
| if (!Array.isArray(input)) return makeIdFilterToMatchWithQuery( | ||
| // Array.isArray cannot narrow the type | ||
| // https://github.com/microsoft/TypeScript/issues/17002 | ||
| input | ||
| ); | ||
| return input.map((i) => makeIdFilterToMatchWithQuery(i)); | ||
| } | ||
| function makeIdFilterToMatchWithQuery(input) { | ||
| if (typeof input === "string") return `${input}{?*,}`; | ||
| return makeRegexIdFilterToMatchWithQuery(input); | ||
| } | ||
| function makeRegexIdFilterToMatchWithQuery(input) { | ||
| return new RegExp( | ||
| // replace `$` with `(?:\?.*)?$` (ignore `\$`) | ||
| input.source.replace(/(?<!\\)\$/g, "(?:\\?.*)?$"), | ||
| input.flags | ||
| ); | ||
| } | ||
| //#endregion | ||
| exports.and = and; | ||
| exports.code = code; | ||
| exports.exactRegex = exactRegex; | ||
| exports.exclude = exclude; | ||
| exports.exprInterpreter = exprInterpreter; | ||
| exports.id = id; | ||
| exports.include = include; | ||
| exports.interpreter = interpreter; | ||
| exports.interpreterImpl = interpreterImpl; | ||
| exports.makeIdFiltersToMatchWithQuery = makeIdFiltersToMatchWithQuery; | ||
| exports.moduleType = moduleType; | ||
| exports.not = not; | ||
| exports.or = or; | ||
| exports.prefixRegex = prefixRegex; | ||
| exports.queries = queries; | ||
| exports.query = query; |
-116
| //#region src/composable-filters.d.ts | ||
| type StringOrRegExp = string | RegExp; | ||
| type PluginModuleType = "js" | "jsx" | "ts" | "tsx" | "json" | "text" | "base64" | "dataurl" | "binary" | "empty" | (string & {}); | ||
| type FilterExpressionKind = FilterExpression["kind"]; | ||
| type FilterExpression = And | Or | Not | Id | ModuleType | Code | Query; | ||
| type TopLevelFilterExpression = Include | Exclude; | ||
| declare class And { | ||
| kind: "and"; | ||
| args: FilterExpression[]; | ||
| constructor(...args: FilterExpression[]); | ||
| } | ||
| declare class Or { | ||
| kind: "or"; | ||
| args: FilterExpression[]; | ||
| constructor(...args: FilterExpression[]); | ||
| } | ||
| declare class Not { | ||
| kind: "not"; | ||
| expr: FilterExpression; | ||
| constructor(expr: FilterExpression); | ||
| } | ||
| interface QueryFilterObject { | ||
| [key: string]: StringOrRegExp | boolean; | ||
| } | ||
| interface IdParams { | ||
| cleanUrl?: boolean; | ||
| } | ||
| declare class Id { | ||
| kind: "id"; | ||
| pattern: StringOrRegExp; | ||
| params: IdParams; | ||
| constructor(pattern: StringOrRegExp, params?: IdParams); | ||
| } | ||
| declare class ModuleType { | ||
| kind: "moduleType"; | ||
| pattern: PluginModuleType; | ||
| constructor(pattern: PluginModuleType); | ||
| } | ||
| declare class Code { | ||
| kind: "code"; | ||
| pattern: StringOrRegExp; | ||
| constructor(expr: StringOrRegExp); | ||
| } | ||
| declare class Query { | ||
| kind: "query"; | ||
| key: string; | ||
| pattern: StringOrRegExp | boolean; | ||
| constructor(key: string, pattern: StringOrRegExp | boolean); | ||
| } | ||
| declare class Include { | ||
| kind: "include"; | ||
| expr: FilterExpression; | ||
| constructor(expr: FilterExpression); | ||
| } | ||
| declare class Exclude { | ||
| kind: "exclude"; | ||
| expr: FilterExpression; | ||
| constructor(expr: FilterExpression); | ||
| } | ||
| declare function and(...args: FilterExpression[]): And; | ||
| declare function or(...args: FilterExpression[]): Or; | ||
| declare function not(expr: FilterExpression): Not; | ||
| declare function id(pattern: StringOrRegExp, params?: IdParams): Id; | ||
| declare function moduleType(pattern: PluginModuleType): ModuleType; | ||
| declare function code(pattern: StringOrRegExp): Code; | ||
| declare function query(key: string, pattern: StringOrRegExp | boolean): Query; | ||
| declare function include(expr: FilterExpression): Include; | ||
| declare function exclude(expr: FilterExpression): Exclude; | ||
| /** | ||
| * convert a queryObject to FilterExpression like | ||
| * ```js | ||
| * and(query(k1, v1), query(k2, v2)) | ||
| * ``` | ||
| * @param queryFilterObject The query filter object needs to be matched. | ||
| * @returns a `And` FilterExpression | ||
| */ | ||
| declare function queries(queryFilter: QueryFilterObject): And; | ||
| declare function interpreter(exprs: TopLevelFilterExpression | TopLevelFilterExpression[], code?: string, id?: string, moduleType?: PluginModuleType): boolean; | ||
| interface InterpreterCtx { | ||
| urlSearchParamsCache?: URLSearchParams; | ||
| } | ||
| declare function interpreterImpl(expr: TopLevelFilterExpression[], code?: string, id?: string, moduleType?: PluginModuleType, ctx?: InterpreterCtx): boolean; | ||
| declare function exprInterpreter(expr: FilterExpression, code?: string, id?: string, moduleType?: PluginModuleType, ctx?: InterpreterCtx): boolean; | ||
| //#endregion | ||
| //#region src/simple-filters.d.ts | ||
| /** | ||
| * Constructs a RegExp that matches the exact string specified. | ||
| * | ||
| * This is useful for plugin hook filters. | ||
| * | ||
| * @param str the string to match. | ||
| * @param flags flags for the RegExp. | ||
| */ | ||
| declare function exactRegex(str: string, flags?: string): RegExp; | ||
| /** | ||
| * Constructs a RegExp that matches a value that has the specified prefix. | ||
| * | ||
| * This is useful for plugin hook filters. | ||
| * | ||
| * @param str the string to match. | ||
| * @param flags flags for the RegExp. | ||
| */ | ||
| declare function prefixRegex(str: string, flags?: string): RegExp; | ||
| type WidenString<T> = T extends string ? string : T; | ||
| /** | ||
| * Converts a id filter to match with an id with a query. | ||
| * | ||
| * @param input the id filters to convert. | ||
| */ | ||
| declare function makeIdFiltersToMatchWithQuery<T extends string | RegExp>(input: T): WidenString<T>; | ||
| declare function makeIdFiltersToMatchWithQuery<T extends string | RegExp>(input: readonly T[]): WidenString<T>[]; | ||
| declare function makeIdFiltersToMatchWithQuery(input: string | RegExp | readonly (string | RegExp)[]): string | RegExp | (string | RegExp)[]; | ||
| //#endregion | ||
| export { FilterExpression, FilterExpressionKind, QueryFilterObject, TopLevelFilterExpression, and, code, exactRegex, exclude, exprInterpreter, id, include, interpreter, interpreterImpl, makeIdFiltersToMatchWithQuery, moduleType, not, or, prefixRegex, queries, query }; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
15
150%617
3.01%1
-50%0
-100%78
Infinity%23220
-2.74%1
Infinity%