Spintax 用于 JavaScript 和 TypeScript

spintax 引擎现已作为独立 npm 包发布:@spintax/core。零依赖,MIT 许可,不绑定任何框架——驱动 WordPress 插件的那套 parse / render / validate 原语,现在任何能跑 JavaScript 的地方都能用。

这是什么

@spintax/core 是一个开源、不绑定框架的 spintax 引擎,面向 JavaScript 和 TypeScript。它是 Spintax WordPress 插件同伴项目——同一套语法的独立 TypeScript 实现,零 WordPress 依赖。一个引擎,多个表面。

  • 运行时零依赖。在 Cloudflare Workers、Node 18+ 和浏览器里不加修改直接运行。
  • ESM 优先,兼发 CJS。两套模块体系都附带 .d.ts 类型。
  • MIT 许可。WordPress 插件保持 GPL;MIT/Expat 与 GPL 兼容,两者干净共存。
  • 一致性有机器验证——与 PHP 插件共享一套 golden corpus,不是承诺,是机器检查的闸门。

安装

npm install @spintax/core

快速上手

import { render, validate, extract } from '@spintax/core';

render('{Hello|Hi|Hey} %name%!', { context: { name: 'Ada' }, seed: 42 });
// → "Hi Ada!"  (deterministic for a given seed; post-processed by default)

validate('{a|b');          // → [{ severity: 'error', code: 'bracket.unclosed', … }]
extract('%title% {?promo?Sale}'); // → { refs: ['title', 'promo'], sets: [], defs: [], includes: [] }

带上 seedrender 完全可复现;不带则每次调用都从模板空间里抽一个新的随机结果。

API

一个小而锋利的核心。每个函数都既接受原始 string接受已解析的 Ast(来自 parse)——调用方可以解析一次、反复使用。

函数作用
parse(src)解析一次,得到不透明、带版本的 Ast 供复用——这是内存里的性能句柄,不是序列化格式。
render(input, opts?)渲染成一个字符串。宽容——坏掉的标记也绝不抛异常。外观后处理(空格、大小写、URL/邮箱防护)默认开启。
validate(input, opts?)返回诊断。有效 ⇔ 没有 severity:'error'。未解析的 %var% 是警告而非错误。复数结论随 locale 而定。
extract(input)列出变量引用 refs#set#def 名称和 #include 目标——为异步 include 的两阶段预取提供依据。
analyze(input, opts?)extract + validate + 尽力而为的构件统计。给工具用的统计层。
neutralize(value)防护来自数据的不可信文本,使其不会被再次解释为 spintax 标记。文本级防护,不是 HTML 转义。

render 接受 context(变量表)、seedlocale(复数形式桶,例如 ru 对应三形态规则)、可选的宿主注入 includeResolverpostProcess 开关,以及限制嵌套与 #include 深度的 maxDepth

还是你已经认识的那套语法

这是完整的 spintax 语法面——语法参考逐字适用。

构件示例含义
枚举{a|b|c}选一个(可嵌套:{a|{b|c}}
排列[a|b|c]取 N 个、打乱、拼接——分隔符可配置
变量%var%代入上下文中的值
局部 set#set %v% = value定义变量(单行);是宏——每次引用重新抽取
局部 def#def %v% = value形式相同,但每次渲染只解析一次、处处一致
条件{?VAR?then|else}按值分支(指南
复数{plural %n%: one|few|many}按 locale 做语法一致(指南
Include#include "slug-or-id"嵌入另一个模板(由宿主解析)
注释/# … #/渲染前剔除

与 WordPress 插件的一致性

“独立实现,但在关键处保持一致”是这个包的全部意义——而且是被强制执行的,不是被打算的。一套共享 golden corpus(语言无关的用例:(template, context, locale, seed) → expected)同时被 PHP 插件的测试套件和这个 TypeScript 套件消费。

  • 确定性行为纳入一致性闸门:校验结论、复数形式、条件真值、#set/#def 解析和后处理流水线,在两个引擎里断言完全相同的输出。
  • 随机选择不纳入。带 seed 的渲染在同一引擎内可复现;跨引擎的随机序列一致是有意为之的非目标。两边都给你合法的结果,只是不保证同一个。

它不是对 GPL PHP 代码的逐行移植——而是从行为契约加上这套语料库重新实现的,这正是它能干净地保持 MIT 的原因。

一个引擎,多个表面

这个包是整个生态共享的运行时——下面每个表面都是同一个公开 API 的消费者,从来不是私有分叉:

  • 本站的演练场/play/EN)在你的浏览器里客户端渲染。
  • 一个 Cloudflare Worker 参考 API——通过 HTTP 校验和预览渲染。
  • Telegram 机器人 @spintaxnetbot——贴进模板,直接在聊天里拿到校验结果和几个渲染变体。

因为这些示例只 import @spintax/core、别无其他,每一个都在证明这个 API 不用被污染也够用。Worker 和机器人能用,你的项目就能用。