Files
ff-dist/virtual-fs.d.ts
what acbff01332 fix: 补回被合成入口丢掉的 default 导出
button/container/data-converter/data-list/grid-layout/grid-layout-form/
res-ws/virtual-fs 这几个入口的 index.js 都用 export { default as X } from './xxx'
转发了 default 导出,但同级有手写 types/ 目录时会触发合成入口逻辑,用
export * from './index' 拼入口文件,而 export * 在 ES 模块语义里不会带出 default,
导致这些包的 default 导出(部分甚至连实现本身,如 DataConverter、ResWs 整个类)
被 tree-shake 掉,没有出现在最终产物里。
2026-09-23 11:13:04 +08:00

408 lines
15 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { WidgetType, WidgetContainerProps } from './button';
/**
* 把 VirtualFS 里某个路径下的结构递归转换成 antd Tree 组件可用的节点结构
* (目录排在文件前面,各自按名称排序)
* @param {VirtualFS} vfs - 虚拟文件系统实例
* @param {string} [pathStr] - 起始路径,默认根目录
* @param {string} [prefix] - 拼在 key 前面的前缀,用于避免多棵树的 key 冲突
* @returns {Promise<{title: string, key: string, isLeaf: boolean, children?: Array}|null>}
* 树节点;路径无效/出错时返回 null
*/
declare function toTreePaths(vfs: VirtualFS, pathStr?: string, prefix?: string): Promise<{
title: string;
key: string;
isLeaf: boolean;
children?: any[];
} | null>;
/**
* 内存中的虚拟文件系统,提供类似 Node fs 的增删改查 API(stat/dir/readFile/writeFile/mkdir/...),
* 支持工作目录(scope)、变更订阅(subscribe)和文件查找(findFiles)
*/
declare class VirtualFS {
/**
* 创建一个虚拟文件系统实例
* @param {Object|Object[]|null} [initialStructure] - 初始文件系统结构
* - 如果是数组:将作为根目录的 children
* - 如果是对象且 name 为 '/':将作为根节点
* - 如果是对象且 name 不为 '/':将添加到根目录的 children
* - 如果为 null 或 undefined:创建空的文件系统
* @param {string} [working='/'] - 工作目录路径,默认为根目录
*
* @example
* // 创建空文件系统
* const vfs1 = new VirtualFS();
*
* @example
* // 使用数组初始化
* const vfs2 = new VirtualFS([
* { name: 'file.txt', type: 'file', content: 'hello' },
* { name: 'src', type: 'dir', children: [] }
* ]);
*
* @example
* // 使用根节点对象初始化
* const vfs3 = new VirtualFS({
* name: '/',
* type: 'dir',
* children: [{ name: 'file.txt', type: 'file', content: 'hello' }],
* lastModified: Date.now()
* });
*
* @example
* // 使用子节点对象初始化
* const vfs4 = new VirtualFS({
* name: 'src',
* type: 'dir',
* children: []
* });
*
* @example
* // 指定工作目录
* const vfs5 = new VirtualFS(rootNode, '/src');
*/
constructor(initialStructure?: any | any[] | null, working?: string);
root: any;
/**
* 获取文件/目录的状态信息
* @param {string} pathStr - 文件或目录路径(相对于工作目录或绝对路径)
* @returns {Promise<{isFile: () => boolean, isDirectory: () => boolean, lastModified: number}>}
* @throws {Error} 路径无效或不存在
*/
stat(pathStr: string): Promise<{
isFile: () => boolean;
isDirectory: () => boolean;
lastModified: number;
}>;
/**
* 列出目录下的所有子项名称
* @param {string} pathStr - 目录路径
* @returns {Promise<string[]>} 子项名称数组
* @throws {Error} 路径无效、不存在或不是目录
*/
dir(pathStr: string): Promise<string[]>;
/**
* 读取文件内容
* @param {string} pathStr - 文件路径
* @returns {Promise<string>} 文件内容,没有内容时返回空字符串
* @throws {Error} 路径无效、不存在或是目录
*/
readFile(pathStr: string): Promise<string>;
/**
* 写入文件内容,文件不存在则创建,存在则覆盖
* @param {string} pathStr - 文件路径
* @param {string} content - 文件内容
* @returns {Promise<void>}
* @throws {Error} 路径无效、父目录不存在或父路径不是目录
*/
writeFile(pathStr: string, content: string): Promise<void>;
/**
* 创建目录
* @param {string} pathStr - 目录路径
* @param {Object} [options] - 选项
* @param {boolean} [options.recursive] - 是否递归创建缺失的父目录(类似 mkdir -p)
* @returns {Promise<void>}
* @throws {Error} 路径无效、父目录不存在/不是目录,或(非 recursive 时)目录已存在
*/
mkdir(pathStr: string, options?: {
recursive?: boolean;
}): Promise<void>;
/**
* 删除文件
* @param {string} pathStr - 文件路径
* @returns {Promise<void>}
* @throws {Error} 路径无效、不存在或是目录
*/
unlink(pathStr: string): Promise<void>;
/**
* 删除目录
* @param {string} pathStr - 目录路径
* @param {Object} [options] - 选项
* @param {boolean} [options.recursive] - 目录非空时是否强制删除(类似 rm -rf)
* @returns {Promise<void>}
* @throws {Error} 路径无效、不存在、不是目录,或(非 recursive 时)目录非空
*/
rmdir(pathStr: string, options?: {
recursive?: boolean;
}): Promise<void>;
/**
* 重命名/移动文件或目录
* @param {string} oldPath - 原路径
* @param {string} newPath - 目标路径
* @returns {Promise<void>}
* @throws {Error} 路径无效、原路径不存在、目标父目录不存在,或目标路径已存在
*/
rename(oldPath: string, newPath: string): Promise<void>;
/**
* 判断路径是否存在
* @param {string} pathStr - 文件或目录路径
* @returns {Promise<boolean>} 是否存在(路径无效时也返回 false)
*/
exists(pathStr: string): Promise<boolean>;
/**
* 获取整个文件系统的最后修改时间
* @returns {number} 时间戳(毫秒)
*/
getLastModified(): number;
/**
* 订阅文件系统变更事件
* @param {Function} callback - 回调函数,接收事件对象
* @returns {Function} 取消订阅的函数
*
* 事件对象格式:
* - action: 'create' | 'update' | 'delete' | 'rename'
* - path: 文件或目录的路径
* - type: 'file' | 'dir'
* - timestamp: 操作时间戳
* - oldPath: (仅 rename 事件) 旧路径
*
* @example
* // 订阅文件系统变更
* const unsubscribe = vfs.subscribe((event) => {
* console.log(`${event.action} ${event.type}: ${event.path}`);
* // 输出示例: "create file: /src/index.js"
* });
*
* // 监听特定类型的变更
* const unsubscribe = vfs.subscribe((event) => {
* if (event.action === 'create' && event.type === 'file') {
* console.log('New file created:', event.path);
* }
* });
*
* // 取消订阅
* unsubscribe();
*/
subscribe(callback: Function): Function;
/**
* 获取当前工作目录
* @returns {string} 当前工作目录路径
*/
getWorkingDirectory(): string;
/**
* 打开指定路径的目录,返回一个新的 VirtualFS 实例
*
* 注意:返回的实例与原实例共享同一个节点树,对新实例的修改会影响原实例
*
* @param {string} pathStr - 要打开的目录路径,默认为根目录
* @returns {VirtualFS} 新的 VirtualFS 实例,以指定目录为根(共享引用)
* @throws {Error} 如果路径无效、不存在或不是目录
*
* @example
* const vfs = new VirtualFS();
* await vfs.mkdir('/src');
* await vfs.writeFile('/src/index.js', 'content1');
*
* const srcVfs = vfs.scope('/src');
* await srcVfs.writeFile('/index.js', 'content2'); // 修改文件
*
* // 原实例也会看到修改
* const content = await vfs.readFile('/src/index.js');
* console.log(content); // 'content2'
*/
scope(pathStr?: string): VirtualFS;
/**
* 在指定目录下查找匹配的文件
* @param {string} dirPath - 要搜索的目录路径
* @param {string|string[]|Function} patterns - 文件名模式,支持精确匹配、glob 通配符或过滤函数
* @param {Object} options - 选项对象
* @param {boolean} options.recursive - 是否递归搜索子目录(默认 false)
* @param {boolean|string} options.fullPath - 返回路径的类型(默认 false)
* - false:返回相对路径或文件名
* - true 或 'working':返回基于工作目录的相对路径(不带前导 /)
* * 例如:'src/index.js', 'utils/helper.js'
* - 'root':返回基于根目录的绝对路径(带前导 /)
* * 例如:'/src/index.js', '/src/utils/helper.js'
* @returns {Promise<string[]>} 匹配的文件名数组
* @throws {Error} 如果路径无效、目录不存在或路径不是目录
*
* 支持的模式类型:
* 1. 精确匹配: 'index.js' - 查找具体的文件名
* 2. 通配符 *: '*.js' - 匹配任意数量的字符
* 3. 通配符 ?: 'App.?sx' - 匹配单个字符
* 4. 大括号展开: 'index.{js,jsx,ts}' - 匹配多个可选值
* 5. 数组模式: ['*.js', 'App.*', 'package.json'] - 组合多个模式
* 6. 过滤函数: (filename) => boolean - 自定义过滤逻辑
*
* 使用示例:
* ```javascript
* // 精确查找单个文件
* await vfs.findFiles('/src', 'index.js')
* // 返回: ['index.js'] (如果存在)
*
* // 查找多个精确文件
* await vfs.findFiles('/src', ['index.js', 'App.jsx', 'main.ts'])
* // 返回: ['index.js', 'App.jsx'] (返回存在的文件)
*
* // 使用通配符查找所有 .js 文件
* await vfs.findFiles('/src', '*.js')
* // 返回: ['index.js', 'main.js', 'utils.js']
*
* // 使用 ? 匹配单个字符
* await vfs.findFiles('/src', 'App.?sx')
* // 返回: ['App.jsx', 'App.tsx']
*
* // 使用大括号展开
* await vfs.findFiles('/src', 'index.{js,jsx,ts,tsx}')
* // 返回: ['index.js', 'index.jsx'] (返回存在的变体)
*
* // 组合通配符和大括号
* await vfs.findFiles('/src', '*.{js,jsx}')
* // 返回: ['index.js', 'App.jsx', 'main.js']
*
* // 混合精确匹配和模式
* await vfs.findFiles('/src', ['package.json', '*.ts', 'index.{js,jsx}'])
* // 返回所有匹配的文件
*
* // 使用过滤函数
* await vfs.findFiles('/src', (filename) => filename.startsWith('test'))
* // 返回: ['test-utils.js', 'test-helpers.js']
*
* // 使用过滤函数 - 复杂条件
* await vfs.findFiles('/src', (filename) => {
* return filename.endsWith('.js') && filename.length > 10
* })
* // 返回所有长度大于10的 .js 文件
*
* // 递归搜索所有子目录
* await vfs.findFiles('/src', '*.js', { recursive: true })
* // 返回: ['index.js', 'utils/helper.js', 'components/Button.js']
*
* // 递归搜索 + 过滤函数
* await vfs.findFiles('/src', (filename) => filename.includes('test'), { recursive: true })
* // 返回: ['test.js', 'utils/test-helper.js', 'components/Button.test.js']
*
* // 返回基于工作目录的完整路径
* await vfs.findFiles('/src', '*.js', { fullPath: true })
* // 或者
* await vfs.findFiles('/src', '*.js', { fullPath: 'working' })
* // 返回: ['src/index.js', 'src/main.js'] (相对路径,不带前导 /)
*
* // 返回基于根目录的完整路径
* await vfs.findFiles('/src', '*.js', { fullPath: 'root' })
* // 返回: ['/src/index.js', '/src/main.js'] (绝对路径,带前导 /)
*
* // 递归搜索 + 根目录完整路径
* await vfs.findFiles('/src', '*.js', { recursive: true, fullPath: 'root' })
* // 返回: ['/src/index.js', '/src/utils/helper.js', '/src/components/Button.js']
* ```
*/
findFiles(dirPath: string, patterns: string | string[] | Function, options?: {
recursive: boolean;
fullPath: boolean | string;
}): Promise<string[]>;
#private;
}
// ===== 用户数据结构(复用类型,JSDoc 无法跨文件引用,放 .d.ts) =====
interface UserRoleBinding {
user_uuid: string
role_uuid: string
created_at: string
updated_at: string
created_user: string
owned_user: string
}
interface UserInfo {
uuid: string
username: string
nickname: string
email: string
last_login_ip: string
is_active: 0 | 1
UserRole: UserRoleBinding[]
[key: string]: unknown
}
interface MenuItem {
/** 菜单唯一标识 */
uuid: string
/** 菜单显示名称 */
name: string
/** 图标 class 名 */
icon: string
/** 行为目标(组件标识 / 路由 uuid 等),含义随 widgetType 而定 */
widget: string
/** 行为类型 */
widgetType: WidgetType
/** 传给目标组件的 props 映射配置 */
widgetProps: Record<string, unknown>
/** 传给目标组件的 $setting 配置 */
widgetSetting: Record<string, unknown>
/** 弹窗容器配置 */
widgetContainerSetting: WidgetContainerProps
/** 子菜单 */
children?: MenuItem[]
}
interface RouteItem {
/** 路由唯一标识 */
uuid: string
/** 路由名称 */
name: string
/** react-router path,支持动态参数(如 /page/:id) */
uri: string
/** 是否为布局路由(外层 layout,不直接渲染页面内容) */
isLayout: boolean
/** 是否需要登录才能访问 */
isLogin: boolean
/** 是否为手机端专属路由 */
isPhone: boolean
/** 路由类型 */
type: Exclude<WidgetType, 'redirect'>
/** 是否精确匹配路径 */
exact: boolean
/** widget 标识(等同于 ButtonProps.widget),经 core.getWidgetComponent 加载 */
component: string
/** 传给页面组件的 props 映射配置 */
widgetProps: Record<string, unknown>
/** 传给页面组件的 $setting 配置 */
widgetSetting: Record<string, unknown>
/** 弹窗容器配置 */
widgetContainerSetting: WidgetContainerProps
/** 附加配置(如 layout 标识等) */
extra?: Record<string, unknown>
}
// ===== http — Proxy 模式产生交叉类型,JSDoc 无法表达 =====
/** 每次请求自动附加的请求头 */
interface HttpHeaders {
/** 客户端平台标识,固定为 'web' */
Platform: string
/** SaaS 租户标识,单租户时为 null */
SaaS: string | null
/** JWT Bearer token,未登录时为 undefined */
Authorization: string | undefined
}
// ===== func — ff-worker-pipe 无类型文件,显式声明 =====
/**
* 基于 Worker 的表达式执行引擎单例;
* exec 在独立 Worker 上下文中求值一段 JS 表达式/源码
*/
interface WorkerPipeInstance {
/**
* 在 Worker 上下文中执行一段 JS 表达式
* @param expression 要执行的表达式字符串
* @param args 传给表达式的参数(可在表达式内作为第一个参数使用)
* @param fns 注入到表达式执行作用域的额外可调用函数
* @param session 会话标识;相同 session 共享 Worker 侧工作区(this)
*/
exec: (
expression: string,
args?: Record<string, unknown>,
fns?: Record<string, Function>,
session?: string
) => Promise<unknown>
/** 清除指定 session 的 Worker 侧工作区 */
clear: (session: string) => void
}
export { VirtualFS as default, toTreePaths };
export type { HttpHeaders, MenuItem, RouteItem, UserInfo, UserRoleBinding, WorkerPipeInstance };