安装
npm install subscript
yarn add subscript
pnpm add subscript
bun add subscript
README

subscript

Modular expression parser & evaluator

build npm size microjs

import subscript from 'subscript'

let fn = subscript('a + b * 2')
fn({ a: 1, b: 3 })  // 7
  • Modular — 40+ pluggable syntax features, see playground
  • Universal — minimal syntax tree, see spec
  • Fast — efficient parser, see benchmarks
  • Small — ~2KB core, runs in browser/node
  • Safe — sandboxed, no prototype access
  • Metacircular — parses and compiles itself

Useful for: templates, calculators, sandboxes, safe eval, language subsets, custom DSLs, preprocessors.

Presets

Subscript – common expressions:

import subscript from 'subscript'

subscript('a.b + c * 2')({ a: { b: 1 }, c: 3 })  // 7

Justin – JSON + expressions + templates + arrows:

import justin from 'subscript/justin.js'

justin('{ x: a?.b ?? 0, y: [1, ...rest] }')({ a: null, rest: [2, 3] })
// { x: 0, y: [1, 2, 3] }

Jessie – JSON + expressions + statements, functions (JS subset):

import jessie from 'subscript/jessie.js'

let fn = jessie(`
  function factorial(n) {
    if (n <= 1) return 1
    return n * factorial(n - 1)
  }
  factorial(5)
`)
fn({})  // 120

Each preset has a parse-only entry — subscript/feature/{subscript,justin,jessie} — that drops the runtime (~50% smaller) for consumers that only need the AST. See docs for full description.

Syntax tree

Expressions parse to minimal JSON-compatible tree structure:

import { parse } from 'subscript'

parse('a + b * 2')
// ['+', 'a', ['*', 'b', [, 2]]]

// node kinds
'x'             // identifier — resolve from context
[, value]       // literal — return as-is (empty slot = data)
[op, ...args]   // operation — apply operator

See spec.md.

Extension

Add operators, literals or custom syntax. binary/unary/token/keyword register parsers; operator registers compilers — pair them as needed:

import justin, { binary, operator, compile } from 'subscript/justin.js'

// add intersection operator
binary('∩', 80)  // register parser
operator('∩', (a, b) => (  // register compiler
  a = compile(a), b = compile(b),
  ctx => a(ctx).filter(x => b(ctx).includes(x))
))

justin('[1,2,3] ∩ [2,3,4]')({})  // [2, 3]

For parse-only consumers, register only the parse half:

import { binary } from 'subscript/feature/justin.js'
binary('∩', 80)

See docs.md for full API.

Safety

Blocked by default:

  • __proto__, __defineGetter__, __defineSetter__
  • constructor, prototype
  • Global access (only context is visible)
subscript('constructor.constructor("alert(1)")()')({})
// undefined (blocked)

Performance

Parsing a + b * c - d / e + f.g[0](h) + i.j, 30k iterations — each iteration parses an unseen source, so source-keyed compile caches (new Function, angular-expressions) don't help:

Parse:
  subscript     26ms
  justin        35ms
  cel-js        45ms
  jsep          46ms
  jessie        51ms   ← JS subset (statements + functions)
  expr-eval     74ms
  oxc           86ms   ← full JS parser (native Rust)
  mathjs       156ms
  new Function 166ms
  jexl         304ms
  angular-expr  48s

Eval:
  new Function 0.2ms
  subscript    1.7ms
  cel-js        10ms
  mathjs        10ms
  expression-eval 24ms
  angular-expr  44ms

Run via node --import ./test/https-loader.js test/benchmark.js.

Utils

Codegen

Convert tree back to code:

import { codegen } from 'subscript/util/stringify.js'

codegen(['+', ['*', 'min', [,60]], [,'sec']])
// 'min * 60 + "sec"'

Bundle

Bundle imports into a single file:

// Node.js
import { bundleFile } from 'subscript/util/bundle.js'
console.log(await bundleFile('jessie.js'))

// Browser / custom sources
import { bundle } from 'subscript/util/bundle.js'
console.log(await bundle('main.js', {
  'main.js': `import { x } from './lib.js'; export default x * 2`,
  'lib.js': `export const x = 21`
}))
// → "const x = 21;\nexport { x as default }"

Used by

  • jz — JS subset → WASM compiler
  • sprae — DOM framework

Alternatives

cel-js, jsep, jexl, expr-eval, math.js, mozjexl, jexpr, expression-eval, string-math, nerdamer, math-codegen, math-parser, nx-compile, built-in-math-eval


版本列表
10.7.0 2026-07-13
10.5.2 2026-07-02
10.5.1 2026-07-02
10.5.0 2026-07-02
10.4.17 2026-05-29
10.4.16 2026-05-28
10.4.15 2026-05-21
10.4.14 2026-05-20
10.4.13 2026-05-20
10.4.12 2026-05-18
10.4.11 2026-05-18
10.4.10 2026-05-15
10.4.9 2026-05-14
10.4.8 2026-05-13
10.4.7 2026-05-12
10.4.6 2026-05-12
10.4.5 2026-05-12
10.4.4 2026-05-12
10.4.3 2026-05-12
10.4.2 2026-05-08
10.4.1 2026-05-07
10.4.0 2026-05-07
10.3.6 2026-05-06
10.3.5 2026-05-03
10.3.4 2026-05-03
10.3.3 2026-04-20
10.3.2 2026-04-11
10.3.1 2026-04-08
10.2.0 2026-02-01
10.1.8 2026-01-31
10.1.7 2026-01-31
10.1.6 2026-01-31
10.1.5 2026-01-30
10.1.4 2026-01-30
10.1.3 2026-01-29
10.1.2 2026-01-24
10.1.1 2026-01-22
10.1.0 2026-01-22
10.0.4 2026-01-21
10.0.3 2026-01-19
10.0.2 2026-01-18
10.0.1 2026-01-18
10.0.0 2026-01-17
9.2.0 2026-01-12
9.1.0 2025-02-20
9.0.2 2025-02-17
9.0.1 2025-01-01
9.0.0 2024-11-09
8.6.0 2024-10-01
8.5.0 2024-10-01
8.4.1 2024-09-27
8.4.0 2024-06-15
8.3.7 2024-06-11
8.3.6 2024-06-09
8.3.5 2024-05-04
8.3.4 2024-03-07
8.3.3 2024-03-07
8.3.1 2024-03-07
8.3.0 2024-03-07
8.2.2 2024-02-25
8.2.1 2024-02-21
8.2.0 2024-02-21
8.1.3 2024-02-19
8.1.2 2024-02-19
8.1.1 2024-02-19
8.1.0 2024-02-17
8.0.1 2024-02-16
8.0.0 2024-02-16
7.6.2 2024-02-10
7.6.1 2024-02-10
7.6.0 2024-02-10
7.5.5 2024-01-16
7.5.4 2024-01-16
7.5.3 2024-01-16
7.5.2 2024-01-16
7.5.1 2024-01-15
7.5.0 2024-01-15
7.4.6 2023-07-17
7.4.5 2023-07-17
7.4.4 2023-06-20
7.4.3 2023-04-17
7.4.2 2023-04-02
7.4.1 2023-03-09
7.4.0 2023-03-09
7.3.1 2022-05-10
7.3.0 2022-05-10
7.2.0 2022-04-13
7.1.1 2022-04-11
7.1.0 2022-04-11
7.0.7 2022-03-14
7.0.6 2022-03-14
7.0.5 2022-03-14
7.0.4 2022-03-14
7.0.3 2022-02-18
7.0.2 2022-02-18
7.0.1 2022-02-18
7.0.0 2022-02-18
6.4.0 2022-01-26
6.3.1 2022-01-20
6.3.0 2022-01-16
6.2.0 2022-01-11
6.1.0 2022-01-04
6.0.4 2021-12-30
6.0.3 2021-12-30
6.0.2 2021-12-28
6.0.1 2021-12-27
6.0.0 2021-12-27
5.5.2 2021-12-08
5.5.1 2021-12-07
5.5.0 2021-12-07
5.4.0 2021-12-06
5.3.2 2021-12-05
5.3.1 2021-12-02
5.3.0 2021-11-30
5.2.3 2021-11-30
5.2.2 2021-11-30
5.2.1 2021-11-30
5.2.0 2021-11-29
5.1.0 2021-11-29
5.0.0 2021-11-29
4.0.0 2021-11-24
3.0.3 2021-11-20
3.0.2 2021-11-19
3.0.1 2021-11-19
3.0.0 2021-11-18
2.0.0 2021-11-15
1.0.6 2021-11-10
1.0.5 2021-11-05
1.0.4 2021-11-05
1.0.3 2021-11-02
0.0.0 2013-08-11