Spintax для JavaScript и TypeScript

Движок spintax теперь доступен отдельным npm-пакетом: @spintax/core. Ноль зависимостей, лицензия MIT, полная независимость от фреймворка — те же примитивы parse / render / validate, что и в WordPress-плагине, но применимые везде, где работает JavaScript.

Что это

@spintax/core — open-source, framework-agnostic движок spintax для JavaScript и TypeScript. Это компаньон WordPress-плагина Spintaxнезависимая TypeScript-реализация того же синтаксиса, с нулевой зависимостью от WordPress. Один движок, много поверхностей.

  • Ноль зависимостей в рантайме. Работает без изменений на Cloudflare Workers, Node 18+ и в браузере.
  • ESM-first, плюс CJS. Поставляет .d.ts-типы для обеих модульных систем.
  • Лицензия MIT. Плагин остаётся под GPL; MIT/Expat совместим с GPL, так что оба уживаются чисто.
  • Паритет проверяется с PHP-плагином через общий golden corpus — не обещание, а машинно-проверяемый гейт.

Установка

npm install @spintax/core

Быстрый старт

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

render('{Привет|Здравствуйте|Хай} %name%!', { context: { name: 'Ада' }, seed: 42 });
// → "Привет Ада!"  (детерминированно для данного seed; пост-обработка по умолчанию)

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

С seed вызов render полностью воспроизводим. Без него каждый вызов возвращает свежий случайный вариант из пространства шаблона.

API

Маленькое и острое ядро. Каждая функция принимает строку или уже разобранный Ast (из parse) — можно распарсить один раз и переиспользовать.

ФункцияЧто делает
parse(src)Разобрать один раз в непрозрачный версионированный Ast для переиспользования — это handle для производительности, не формат сериализации.
render(input, opts?)Рендер в одну строку. Снисходительный — никогда не бросает исключение на битой разметке. Косметическая пост-обработка (пробелы, регистр, экранирование URL/email) включена по умолчанию.
validate(input, opts?)Вернуть диагностику. Валиден ⇔ нет severity:'error'. Неразрешённая %var% — предупреждение, не ошибка. Вердикты plural зависят от локали.
extract(input)Список ссылок на переменные refs, имён #set и целей #include — основа двухфазного prefetch для асинхронных include.
analyze(input, opts?)extract + validate + best-effort перепись конструкций. Слой статистики для инструментов.
neutralize(value)Экранировать недоверенный текст из данных, чтобы его нельзя было принять за разметку spintax. Text-safe, не HTML-экранирование.

render принимает context (карту переменных), seed, locale (формы plural, например ru для 3-формного правила), опциональный includeResolver от хоста, переключатель postProcess и ограничитель maxDepth для вложенности и #include.

Тот же синтаксис, что вы уже знаете

Это полная поверхность spintax — справочник по синтаксису применим дословно.

КонструкцияПримерСмысл
Перечисление{a|b|c}выбрать одно (вложенность: {a|{b|c}})
Permutation[a|b|c]выбрать N, перемешать, склеить — настраиваемые сепараторы
Переменная%var%подставить значение из контекста
Локальный set#set %v% = valueобъявить переменную (одна строка)
Условие{?VAR?then|else}ветвление по значению (гайд)
Plural{plural %n%: одна|пара|много}согласование с числом по локали (гайд)
Include#include "slug-or-id"встроить другой шаблон (разрешает хост)
Комментарий/# … #/вырезается до рендера

Паритет с WordPress-плагином

«Независимая реализация, но паритет там, где он важен» — это весь смысл пакета, и он обеспечивается, а не декларируется. Общий golden corpus из языконезависимых фикстур (template, context, locale, seed) → expected используется обоими — тест-сьютом PHP-плагина и этим TypeScript-сьютом.

  • Детерминированное поведение под паритетом: вердикты валидации, формы plural, truthiness условий, схлопывание #set и пайплайн пост-обработки дают идентичный вывод в обоих движках.
  • Выбор RNG — нет. Seeded-рендеры воспроизводимы внутри движка; кросс-движковый паритет случайных последовательностей — сознательный non-goal. Валидный вариант вы получите в любом случае, просто не тот же самый.

Это не построчный порт GPL-кода на PHP — он переписан из поведенческого контракта плюс этого корпуса, что и позволяет держать его чисто под MIT.

Один движок, много поверхностей

Пакет — это общий рантайм всей экосистемы; каждая поверхность ниже потребляет тот же публичный API и никогда не является приватным форком:

  • Песочница на этом сайте (/play/) рендерит на клиенте, прямо в браузере.
  • Референсный Cloudflare Worker — валидация и preview-рендер по HTTP.
  • Telegram-бот @spintaxnetbot — вставьте шаблон и получите валидацию плюс несколько готовых вариантов прямо в чате.

Поскольку примеры импортируют @spintax/core и ничего больше, каждый из них доказывает, что API удобен, не засоряя его. Работает для Worker и бота — заработает и в вашем проекте.