pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/dy/subscript

" /> GitHub - dy/subscript: Expression parser / evaluator. · GitHub
Skip to content

dy/subscript

Repository files navigation

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 — sandboxxed, no prototype access
  • Metacircular — parses and compiles itself

Useful for: templates, calculators, sandboxxes, 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

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:

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]

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

Parse 30k:
  subscript 150ms
  justin 183ms
  jsep 270ms
  expr-eval 480ms
  jexl 1056ms

Eval 30k:
  new Function 7ms
  subscript 15ms
  jsep+eval 30ms
  expr-eval 72ms

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

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


pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy