@quickbi/bi-dsl
v1.0.0
Published
QuickBI DSL 包:基于 [valibot](https://valibot.dev/) 的运行时 schema + 反推 TypeScript 类型,描述图表、看板、分析单元、OLAP 查询的契约。
Keywords
Readme
@quickbi/bi-dsl
QuickBI DSL 包:基于 valibot 的运行时 schema + 反推 TypeScript 类型,描述图表、看板、分析单元、OLAP 查询的契约。
依赖约束
禁止依赖任何库,包括本项目内的二方依赖(如 @quickbi/bi-types 等),唯一允许的依赖为 valibot。
所有类型、枚举均在本包内自行定义,保持 bi-dsl 零外部耦合、可独立发布。
命名公约(新增 / 修改任何 schema 前必看)
1. Schema 与 Type 双向命名对称(核心)
type: XxxSpec ⇄ schema: XxxSpecSchema
type: Xxx ⇄ schema: XxxSchema反推公式:type 名 + 'Schema' = schema 名。新增 schema 时按此公式起名,看到任意一边可立即推出另一边。
2. 何时使用 Spec 后缀
边界判定:该结构会被 v.parse(XxxSchema, data) 单独消费吗?
| 情形 | 加 Spec | 例子 |
| --- | --- | --- |
| 顶层 / 可独立消费的 DSL 节点 | ✅ | BarChartSpec、DashboardSpec、AnalysisSpec、JumpSpec、DrillSpec、SortSpec、TopNSpec |
| 嵌入式子配置(仅作为字段类型) | ❌ | Axis、Legend、Label、Tooltip、Encoding、Title |
| 枚举 / 字面量联合 | ❌ | AggType、ChartType、FormatType、LegendPosition |
| 已有语义后缀(Options/Layout/Mapping/Ref/Mode) | ❌ | BarOptions、CommonTableLayout、IndicatorCardMapping、FieldRef、BindingMode |
嵌入式子配置即便看起来像 spec,也别加 Spec —— 名字本身已够语义。
3. 共享 entries 用 xxxBaseEntries(camelCase)
供下游 schema 通过 ...xxxBaseEntries 展开复用:
export const ChartBaseSpecSchema = v.object({...});
/** 共享 entries(供 35 个 encoding 范式图表 schema 通过 `...chartBaseEntries` 展开) */
export const chartBaseEntries = ChartBaseSpecSchema.entries;新增按 <场景>BaseEntries 命名(如 commonSpecEntries、componentBaseEntries)。
4. 图表模块统一三件套(按需取舍)
// 私有 options —— 仅在会被其它图表复用时定义(如 BarOptions 被 bullet/combination 复用)
export const XxxOptionsSchema = v.object({...});
export type XxxOptions = v.InferOutput<typeof XxxOptionsSchema>;
// 完整 options —— 私有 + 通用合并 —— 仅双层场景存在
export const XxxChartOptionsSchema = v.object({
...CommonOptionsSchema.entries,
...XxxOptionsSchema.entries,
});
export type XxxChartOptions = v.InferOutput<typeof XxxChartOptionsSchema>;
// 图表 Spec 主入口(必有)
export const XxxChartSpecSchema = v.object({
...chartBaseEntries,
type: v.literal('xxx'),
options: v.optional(XxxChartOptionsSchema /* 或 XxxOptionsSchema */),
});
export type XxxChartSpec = v.InferOutput<typeof XxxChartSpecSchema>;单层 vs 双层选择标准:私有 XxxOptions 是否被其它图表复用?是 → 双层,否 → 单层(直接用 XxxOptionsSchema)。
5. 文件 / 字面量 / 类型三向对齐
目录/文件: bar-race/index.ts (kebab-case)
type 字面量: type: v.literal('bar_race') (snake_case)
TS 类型: BarRaceChartSpec (PascalCase)新增图表时同步落三处。
模块结构
src/
├── index.ts # 包入口(统一 re-export)
├── olap/ # 取数意图
│ ├── olap-dsl.ts # 当前 DSL(OlapDslSpec)
│ └── olap-dsl-new.ts # [Legacy] 旧版图表级查询,待删除
├── dashboard/ # 看板骨架
│ ├── dashboard-page.ts # DashboardSpec 主入口
│ ├── dashboard-ui.ts
│ ├── dashboard-layout.ts
│ ├── dashboard-card.ts
│ ├── dashboard-component.ts
│ ├── dashboard-interaction.ts
│ ├── dashboard-theme.ts
│ └── dashboard-analysis.ts
└── charts/ # 图表 spec
├── shared/ # 共享 base / encoding / 通用配置
└── <chart-name>/index.ts # 每个图表一个目录使用示例
import * as v from 'valibot';
import { BarChartSpecSchema, type BarChartSpec } from '@quickbi/bi-dsl';
const spec: BarChartSpec = v.parse(BarChartSpecSchema, {
id: 'sale_trend_bar',
type: 'bar',
encoding: { x: 'order.month', y: 'metric.gmv' },
});