first commit

This commit is contained in:
2026-01-09 23:05:52 -05:00
commit dec0c8e4e4
4203 changed files with 824454 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
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 | 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 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 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): boolean;
interface InterpreterCtx {
urlSearchParamsCache?: URLSearchParams;
}
export declare function interpreterImpl(expr: TopLevelFilterExpression[], code?: string, id?: string, moduleType?: PluginModuleType, ctx?: InterpreterCtx): boolean;
export declare function exprInterpreter(expr: FilterExpression, code?: string, id?: string, moduleType?: PluginModuleType, ctx?: InterpreterCtx): boolean;
export {};

View File

@@ -0,0 +1,228 @@
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 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 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) {
let arr = [];
if (Array.isArray(exprs)) {
arr = exprs;
}
else {
arr = [exprs];
}
return interpreterImpl(arr, code, id, moduleType);
}
export function interpreterImpl(expr, code, id, moduleType, ctx = {}) {
let hasInclude = false;
for (const e of expr) {
switch (e.kind) {
case 'include': {
hasInclude = true;
if (exprInterpreter(e.expr, code, id, moduleType, ctx)) {
return true;
}
break;
}
case 'exclude': {
if (exprInterpreter(e.expr, code, id, moduleType)) {
return false;
}
break;
}
}
}
return !hasInclude;
}
export function exprInterpreter(expr, code, id, moduleType, ctx = {}) {
switch (expr.kind) {
case 'and': {
return expr.args.every((e) => exprInterpreter(e, code, id, moduleType, ctx));
}
case 'or': {
return expr.args.some((e) => exprInterpreter(e, code, id, moduleType, ctx));
}
case 'not': {
return !exprInterpreter(expr.expr, code, id, moduleType, ctx);
}
case 'id': {
if (id === undefined) {
throw new Error('`id` is required for `id` expression');
}
if (expr.params.cleanUrl) {
id = cleanUrl(id);
}
return typeof expr.pattern === 'string'
? id === expr.pattern
: expr.pattern.test(id);
}
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.`);
}
}
}

View File

@@ -0,0 +1,28 @@
/**
* 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[];

View File

@@ -0,0 +1,75 @@
/**
* 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;
}

3
node_modules/@rolldown/pluginutils/dist/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
export * from './composable-filters.js';
export * from './filter-vite-plugins.js';
export * from './simple-filters.js';

3
node_modules/@rolldown/pluginutils/dist/index.js generated vendored Normal file
View File

@@ -0,0 +1,3 @@
export * from './composable-filters.js';
export * from './filter-vite-plugins.js';
export * from './simple-filters.js';

View File

@@ -0,0 +1,71 @@
/**
* 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 {};

View File

@@ -0,0 +1,70 @@
/**
* 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);
}

2
node_modules/@rolldown/pluginutils/dist/utils.d.ts generated vendored Normal file
View File

@@ -0,0 +1,2 @@
export declare function cleanUrl(url: string): string;
export declare function extractQueryWithoutFragment(url: string): string;

17
node_modules/@rolldown/pluginutils/dist/utils.js generated vendored Normal file
View File

@@ -0,0 +1,17 @@
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);
}
}