主题
安装
shell
npm install knapKnap 以 ESM 优先,同时也提供 CommonJS 入口,并要求 Node.js 20 或更高版本。
快速开始
ts
import {
createEngine,
standardFilters,
type TemplateVariables,
} from 'knap';
const engine = createEngine({ filters: standardFilters });
const variables: TemplateVariables = {
title: ' An imported note ',
tags: ['reference', 'reading'],
};
const result = await engine.render(
'# {{ title | trim }}\n\n{{ tags | list }}',
{ variables },
);变量与解析器
每次渲染调用时传入变量。Knap 接受未知的应用取值,而不会强制套用 schema。
Knap 并不知道浏览器标签页、vault、选择器或模型是什么。应用可以把这些概念作为普通取值暴露出来,或按需解析它们。
如果某个取值不在变量对象中,宿主可以用 resolveVariable 加载它。本地取值始终优先。当自定义过滤器或解析器需要并非模板变量的宿主数据时,传入一个可选的泛型上下文。
ts
const result = await engine.render('{{ remoteValue | upper }}', {
variables: {},
context: { documentId: 'example' },
resolveVariable: async (name, { context }) => {
if (name === 'remoteValue') {
return loadValue(context.documentId);
}
return undefined;
},
});渲染结果
render() 始终会返回一个包含结构化诊断信息的输出对象。
| 字段 | 类型 | 说明 |
|---|---|---|
output | string | 渲染后的 Markdown。解析失败时为空。 |
errors | TemplateError[] | 致命的语法解析器、校验、解析器或过滤器错误。 |
warnings | TemplateWarning[] | 由过滤器报告的非致命诊断信息。 |
错误包含稳定的 code、message、line 和 column。警告还会标明报告它的过滤器,并在每次渲染中去重。
ts
if (result.errors.length === 0) {
console.log(result.output);
}
const output = await engine.renderOrThrow(
'{{ title | upper }}',
{ variables },
);警告绝不会让 renderOrThrow() 抛出异常。当异常比检查结果更契合宿主应用时,就用它。
引擎方法
| 方法 | 说明 |
|---|---|
createEngine({ filters }) | 用不可变的过滤器注册表创建引擎。 |
engine.render(template, input, options?) | 异步渲染,并返回输出、错误和警告。 |
engine.renderOrThrow(template, input, options?) | 返回输出,或抛出 TemplateRenderError。 |
engine.parse(template) | 返回 AST 与语法解析器诊断信息。 |
engine.validate(templateOrAst) | 校验语法以及过滤器名称或参数。 |
在渲染选项中设置 { trimOutput: false },以保留模板周围的空白。
执行模型
Knap 把模板解析为 AST,并在不使用 eval、也不执行任意 JavaScript 的情况下解释它们。应用控制每个引擎可用的变量、异步解析器和自定义过滤器。
渲染限制
引擎默认应用有限的限制。可以在构造时配置,也可以在渲染选项中传入 limits 对象,为单次渲染覆盖默认限制:
ts
const engine = createEngine({
filters: standardFilters,
allowRegex: false,
limits: {
maxTemplateLength: 100_000,
maxOutputLength: 100_000,
maxValueLength: 1_000_000,
maxOperations: 50_000,
maxDepth: 50,
},
});allowRegex: false 会让 split 把分隔符按字面处理,并拒绝 replace 中的正则搜索。字面替换仍然可用。为兼容起见,正则匹配默认保持启用。在接受不受信任的模板或正则输入时,应在可终止的 worker 或进程中运行渲染,并设置挂钟超时;同线程的 Promise 超时无法中断原生正则匹配。自定义过滤器和解析器属于受信任的宿主代码,如果它们可能阻塞或分配无界数据,同样需要隔离。限制并不是 JavaScript 沙箱。
导出的 defaultRenderLimits 为:1,000,000 个模板字符、5,000,000 个输出字符、每个取值 5,000,000 个字符、100,000 次工作操作、嵌套预算 100。工作包括表达式求值、迭代和取值遍历。长度使用 JavaScript 字符串单位;集合取值检查包含键和结构开销。限制必须是正的安全整数;maxDepth 不能超过 256。超出限制会返回 LIMIT_EXCEEDED,且输出为空。renderOrThrow 照常抛出 TemplateRenderError。parse 和 validate 也会报告嵌套和模板大小的限制。
传入纯数据,而不是带访问器或自定义序列化的对象。属性查找只读取自有数据属性;继承来的取值和 getter 不会被解析。HTML 过滤器会操作标记,但不会对其做净化。
编辑器工具
这些更低层的导出让编辑器可以只做一次词法分析、检查 AST,并独立校验变量或过滤器。
ts
import {
parse,
standardFilterMetadata,
validateFilters,
validateVariables,
} from 'knap';
const parsed = parse(template);
const filterErrors = validateFilters(parsed.ast, standardFilterMetadata);
const variableNames = validateVariables(parsed.ast);当宿主需要在完整渲染之外使用 Knap 过滤器语法时,applyFiltersWithRegistry() 会应用同步的过滤器链。
过滤器回调接收的第一个参数是兼容用的字符串取值。对于需要区分集合与字面 JSON 文本的过滤器,FilterContext.rawValue 保存原始的有类型取值。
包导出
| 导入 | 包含 |
|---|---|
knap | 引擎、语法解析器、词法分析器、标准过滤器、诊断信息和公开类型。 |
knap/html | 依赖 DOM 的 html_to_json 和 remove_html 过滤器。 |
显示输出
Knap 生成 Markdown,其中包含模板或变量提供的任何 HTML。把它作为文本渲染,或使用在把结果插入页面之前会净化 HTML、校验链接协议的 Markdown 渲染器。strip_tags、remove_html 这类 HTML 操作过滤器并非净化器。link 和 image 过滤器会转义字面标签和目的地,并省略 javascript:、vbscript:、data: 目的地;相对链接和 obsidian: 这类应用协议仍然受支持。宿主在显示结果时应应用自己的协议策略。