Add comprehensive frontend UI and distributed infrastructure

Frontend Enhancements:
- Complete React TypeScript frontend with modern UI components
- Distributed workflows management interface with real-time updates
- Socket.IO integration for live agent status monitoring
- Agent management dashboard with cluster visualization
- Project management interface with metrics and task tracking
- Responsive design with proper error handling and loading states

Backend Infrastructure:
- Distributed coordinator for multi-agent workflow orchestration
- Cluster management API with comprehensive agent operations
- Enhanced database models for agents and projects
- Project service for filesystem-based project discovery
- Performance monitoring and metrics collection
- Comprehensive API documentation and error handling

Documentation:
- Complete distributed development guide (README_DISTRIBUTED.md)
- Comprehensive development report with architecture insights
- System configuration templates and deployment guides

The platform now provides a complete web interface for managing the distributed AI cluster
with real-time monitoring, workflow orchestration, and agent coordination capabilities.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-07-10 08:41:59 +10:00
parent fc0eec91ef
commit 85bf1341f3
28348 changed files with 2646896 additions and 69 deletions

25
frontend/node_modules/@rolldown/pluginutils/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,25 @@
MIT License
Copyright (c) 2024-present VoidZero Inc. & Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
end of terms and conditions
The licenses of externally maintained libraries from which parts of the Software is derived are listed [here](https://github.com/rolldown/rolldown/blob/main/THIRD-PARTY-LICENSE).

View File

@@ -0,0 +1,271 @@
//#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.
*
* @example
* ```ts
* import { exactRegex } from '@rolldown/pluginutils';
* const plugin = {
* name: 'plugin',
* resolveId: {
* filter: { id: exactRegex('foo') },
* handler(id) {} // will only be called for `foo`
* }
* }
* ```
*/
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`
* }
* }
* ```
*/
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(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(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;

View File

@@ -0,0 +1,166 @@
//#region src/composable-filters.d.ts
type StringOrRegExp = string | RegExp;
// Inline this type to avoid import it from `rolldown`.
// The only downside is we need to keep it in sync with `rolldown` manually,
// it is alright since it is pretty stable now.
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;
/*
* 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.
*/
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.
*
* @example
* ```ts
* import { exactRegex } from '@rolldown/pluginutils';
* const plugin = {
* name: 'plugin',
* resolveId: {
* filter: { id: exactRegex('foo') },
* handler(id) {} // will only be called for `foo`
* }
* }
* ```
*/
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`
* }
* }
* ```
*/
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) {}
* }
* }
* ```
*/
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 };

View File

@@ -0,0 +1,166 @@
//#region src/composable-filters.d.ts
type StringOrRegExp = string | RegExp;
// Inline this type to avoid import it from `rolldown`.
// The only downside is we need to keep it in sync with `rolldown` manually,
// it is alright since it is pretty stable now.
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;
/*
* 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.
*/
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.
*
* @example
* ```ts
* import { exactRegex } from '@rolldown/pluginutils';
* const plugin = {
* name: 'plugin',
* resolveId: {
* filter: { id: exactRegex('foo') },
* handler(id) {} // will only be called for `foo`
* }
* }
* ```
*/
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`
* }
* }
* ```
*/
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) {}
* }
* }
* ```
*/
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 };

View File

@@ -0,0 +1,255 @@
//#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.
*
* @example
* ```ts
* import { exactRegex } from '@rolldown/pluginutils';
* const plugin = {
* name: 'plugin',
* resolveId: {
* filter: { id: exactRegex('foo') },
* handler(id) {} // will only be called for `foo`
* }
* }
* ```
*/
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`
* }
* }
* ```
*/
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(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(input.source.replace(/(?<!\\)\$/g, "(?:\\?.*)?$"), input.flags);
}
//#endregion
export { and, code, exactRegex, exclude, exprInterpreter, id, include, interpreter, interpreterImpl, makeIdFiltersToMatchWithQuery, moduleType, not, or, prefixRegex, queries, query };

View File

@@ -0,0 +1,36 @@
{
"name": "@rolldown/pluginutils",
"version": "1.0.0-beta.19",
"license": "MIT",
"type": "module",
"repository": {
"type": "git",
"url": "git+https://github.com/rolldown/rolldown.git",
"directory": "packages/pluginutils"
},
"publishConfig": {
"access": "public"
},
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"files": [
"dist"
],
"devDependencies": {
"@types/picomatch": "^4.0.0",
"picomatch": "^4.0.2",
"tsdown": "0.12.8",
"vitest": "^3.0.1"
},
"scripts": {
"build": "tsdown",
"test": "vitest --typecheck"
}
}