Slex 规范 v0.1

这页定义 SlexKit v0 的公开协议:Slex expression envelope、component keys、props、directives、lifecycle 和 runtime API。实现、测试和 host adapter 都应按这里的规则处理。

v0/beta 阶段仍可能调整;协议版本(v0.1)独立于包版本。同一协议版本可能跨越多个包版本保持兼容。

1. Slex expression envelope

标准 Slex expression 是 JavaScript object literal:

{
  slex: "0.1",
  namespace: "example",
  g: {},
  layout: {}
}

字段含义:

运行时也接受裸组件树:当 object keys 看起来是组件 key(包含 :)时,会归一化为默认 envelope。

2. Layout key

组件节点使用 type:name key:

{
  "card:summary": {
    "text:title": { text: "Ready" }
  }
}

保留上下文名称:gstdapi$event$item$index$key

3. Props classification

静态 props

普通 props 原样传给组件:

"badge:state": { label: "Ready", tone: "success" }

$ read-pipes

$ 前缀 prop(排除 $if$for$key)表示动态 read expression。Runtime 求值后去掉 $ 前缀并传给组件:

"text:value": { "$content": "'计数:' + g.count" }
// 解析为: content = "计数:<g.count 的值>"

表达式读取 g、命名组件 state 或 $for context 后,会建立依赖;依赖变化时重新求值。

on* write-pipes

on* 前缀 prop 表示事件 handler statement:

"button:add": { onclick: "g.count++" }

Handler 可访问 $event。Writable components 会在 handler 执行前同步自身 state。

结构 directives

$if$for$key 是 structural directives,不作为 props 传给 renderer。

4. g merge

同一 namespace 的多次 mount 或 ingest 会合并 g

值类型 合并行为
函数 覆盖旧值
数组 整体替换
普通对象 递归深层合并
其他 scalar 覆盖旧值
g 中不存在的 key 保留旧值

layout 不做 deep merge;新 layout 替换旧 layout。

5. Expression context

表达式可以访问:

变量 类型 可用范围
g 响应式 state proxy 始终可用
std SlexKit 纯标准库 始终可用
组件状态 slider.value 命名组件
api 宿主注入对象 存在 api option 时
$event 事件数据 on* handler
$item 当前数组项 $for 上下文
$index 当前数组索引 $for 上下文
$key 当前项 key $for 上下文
命名 $for 别名 "card:user" 可用 user $for 上下文

std 提供确定性的 math、format、units 和 stats helpers。网络、timer、animation、canvas 等敏感能力仍通过宿主注入的 api.* 暴露,并可能受 secure runtime policy 限制。

Trusted mode 使用 new Function() 求值。Secure mode 在 sandbox iframe 内求值,并通过受 policy 控制的 api.* 暴露能力。

表达式求值错误会被捕获,产生包含 namespace 和路径信息的 warning。回退返回上一个已知值。

6. Component instance state

Renderer 注册时声明 state mode:

模式 可写 prop 说明
value value 常见文本、输入、slider
checked checked, value checkbox 等勾选型布尔组件
enabled enabled switch 等启用型布尔组件
readable 可读但不可写
none 不暴露 instance state

命名组件 state 可在表达式中通过组件 name 访问:

{
  layout: {
    "slider:threshold": { value: 50 },
    "text:label": { "$content": "'Threshold: ' + threshold.value" }
  }
}

type: "engineering"input 是 value-mode 组件,额外暴露解析字段。value 保留原始输入字符串,numbervalidprefixunitnormalized 和可选 error 暴露解析后的工程数值。支持科学计数法和 SI 前缀(pnuµmkKMmegGT)加单位后缀。单位只做捕获,不做物理维度换算。

7. $if

$if 控制节点是否渲染:

"card:details": {
  "$if": "g.open",
  "text:body": { text: "Details" }
}

8. $for

$for 为数组生成重复节点:

"text:item": {
  "$for": "g.items",
  "$key": "id",
  "$content": "$item.label"
}

$key 策略

Primitive arrays 应使用 $key: "$value"

$for 阶段

  1. Delete:移除不存在的 keys。
  2. Add/update/reorder:创建新 nodes,更新保留 nodes 的 item/index context,并重排 DOM。
  3. Trim:移除防御性多余 children。

Item index 或 item reference 变化时调用 onUpdate_<name>

9. Lifecycle and cleanup

Runtime 按命名约定调用 hooks:

g.onMount_<name>()      -after component is appended to DOM
g.onUnmount_<name>()    -before component is removed from DOM
g.onUpdate_<name>()     -after $for item changes

组件 renderer 可使用 attachComponentDisposer(el, fn) 注册 cleanup。Runtime 在节点移除、$if 关闭、$for 项删除、root cleanup 或 disposeNamespace() 时调用 disposer。

10. Public runtime API

函数 签名 说明
mount (input, container, options?) => Cleanup 解析、合并 state、渲染组件树
ingest (input) => boolean 仅合并 state,不渲染
boot (options?) => void 增强静态页面的 language-slex blocks
disposeNamespace (namespace) => void 释放 namespace roots、store 和 cache
register (type, renderer, options?) => void 注册组件类型
getRenderer (type) => ComponentRenderer | undefined 查询已注册的 renderer
getIcon (name, state?) => string 同步解析注册或内置图标
loadIcon (name, state?) => Promise<string> 解析图标,未打包时使用 Iconify fallback
registerIcon (name, svg, options?) => void 为所有支持 icon 字段的组件注册一个全局 SVG 图标
registerIcons (icons, options?) => void 注册多个全局 SVG 图标
clearRegisteredIcons () => void 清除所有自定义注册图标
getRegisteredIcon (name, state?) => string 仅查注册图标(无 Phosphor fallback)
normalizeIconName (name) => string 将图标名归一化为 kebab-case 加集合前缀
resolveIconWeight (state?) => IconWeight 从组件状态解析图标 weight
resolveIconifyIcon (name, state?) => {prefix, name} 解析为 Iconify 兼容的 name pair
iconifySvgUrl (name, state?) => string 构建完整 Iconify API SVG URL
configureComponentScope (options) => void 配置框架 adapter flush
attachComponentDisposer (el, dispose) => void 绑定 cleanup 到元素生命周期
createSecureRuntime (policy, adapter?) => SecureRuntimeHandle 创建 policy-gated runtime 实例
mountSecureArtifact (input, container, options) => Cleanup 在 secure sandbox 中挂载
createSlexKitMarkdownRuntimeHost (options?) => MarkdownRuntimeHost 创建 Markdown host 实例
getSlexKitMarkdownRuntimeHost () => MarkdownRuntimeHost 获取或创建全局 Markdown host
installSlexKitMarkdownRuntimeHost (options?) => MarkdownRuntimeHost 安装并返回全局 Markdown host
getSlexKitRuntimeUrl () => string | undefined 获取默认 sandbox runtime URL
setSlexKitRuntimeUrl (url) => void 设置默认 sandbox runtime URL
diagnoseSlexKitSource (source, error) => Diagnostic 定位源码中的语法错误
parseSlexSource (source) => ParseResult 将 Slex source 解析为对象
validateSlexSource (source, options?) => ValidationResult parse-first 验证 source,并返回版本、usage 与稳定 warning codes
runSlexConformance (options?) => ConformanceReport 运行内置标准 conformance fixtures
formatSlexKitDiagnostic (diagnostic) => string 将 diagnostic 格式化为可读字符串

runtime 行为见 Runtime Model

11. Error types

SlexKitSyntaxError

当 Slex source 解析失败时抛出。包含 diagnostic 属性,其中包含 messagelinecolumndetailexcerpt

SlexKitRuntimeError

当 runtime 操作违反 policy 或遇到运行时失败时抛出。属性:kind"policy" | "network" | "timeout")、code(特定错误码字符串)、messageelapsedMs

Diagnostics API:

diagnoseSlexKitSource(source)
formatSlexKitDiagnostic(diagnostic)

12. Markdown language handling

Markdown hosts 只能处理明确标记为 slex 的 fenced code blocks。

不得自动执行:

Host 应保留普通 Markdown fallback,以便不支持 SlexKit 的环境可读。

13. Secure runtime types

type SecureRuntimeHandle = {
  api: SlexKitRuntimeApi;
  dispose: () => void;
};

完整类型(HostRuntimePolicyHostRuntimeAdapterSlexKitRuntimeApiSecureFrameOptionsSecureMountOptions、sandbox message types)见 security runtime contract

14. ToolHost

ToolHost 把 AI tool calls 连接到返回结构化用户输入的交互 UI。它与 display-oriented slex fences 分离。

Public API:

函数 签名 说明
renderToolCall (call, container) => ToolRenderHandle 编译并挂载 tool UI,返回 promise
registerToolTemplate (name, compiler) => void 注册自定义 tool template 编译器

Result 类型:

type ToolResult =
  | { toolCallId?: string; toolName: string; status: "submitted"; value: Record<string, unknown> }
  | { toolCallId?: string; toolName: string; status: "ignored"; value: null };

内置 templates: confirm-actionchoose-optionsoption-listfill-form。Templates 编译成标准 Slex expression,使用 card:toolsubmit:actions 组件。submit:actions 提交工具结果,仅由 tool template 使用,不作为普通 display fence。

完整 template reference 和自定义 template 开发见 ToolHost documentation

15. Icon system

Icon system 提供:

组件使用 kebab-case icon names。API、icon list、命名规则和 custom icon registration 见 Icon system documentation

16. Non-goals

SlexKit v0 不试图提供:

SlexKit 的核心约定是:Markdown-friendly、explicit fence、small interactive fragments、host-chosen trusted/secure mode。