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 掉,没有出现在最终产物里。
408 lines
15 KiB
TypeScript
408 lines
15 KiB
TypeScript
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 };
|