npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tardo/trash

v2.3.0

Published

Command-Oriented Embeddable DSL

Readme

Tests

TraSH is a lightweight, capability-based scripting language for adding programmable workflows to JavaScript applications. The host defines the commands a script can use, validates their arguments, and performs their side effects. Scripts combine those capabilities with expressions, variables, functions, and control flow.

Scripts run through TraSH's parser and virtual machine — no JavaScript eval(). TraSH was extracted from OdooTerminal, where its command-oriented scripting model was developed.

Execution has configurable instruction, source-size, nesting, collection, and string limits, and supports AbortSignal cancellation. See the runtime contract for host-object handling, scope rules, and the limits of these controls.

Why TraSH?

Use TraSH when an application needs more than expressions or data transformations, but should not expose arbitrary JavaScript. It is a middle ground between expression engines and full JavaScript runtimes:

| If you need | Use | | --------------------------------------------------------- | --------------------------------------------------- | | Rules, filters, or JSON transformations | An expression engine such as CEL, JEXL, or JSONata. | | User-defined workflows composed from application commands | TraSH. | | Untrusted scripts or a hardened isolation boundary | A dedicated JavaScript runtime or sandbox. |

This model fits user automations, administrator rules, and agent-generated workflows: the application owns the vocabulary (search, create, notify, and so on), while scripts own the logic that composes it.

TraSH does not grant direct access to Node.js, the DOM, network APIs, or host globals unless the host deliberately returns one through a command or plugin. Its instruction budget and cancellation are cooperative execution controls, not a wall-clock or memory sandbox. For hostile scripts, run parsing and execution in a terminable worker or process; see the runtime contract.

Installation

npm install @tardo/trash

The package is ESM, so consumers must use import or .mjs files.

New to TraSH? Follow the getting started guide to build and run your first script from scratch.

To add JavaScript functionality, follow the first plugin guide.

The optional standard-library plugins are available separately in @tardo/trash-stdlib:

npm install @tardo/trash-stdlib

Flow

The package includes .mjs.flow files generated from its typed source during the build. Flow discovers them automatically, including for deep imports.

import type {CMDDef, VMachineOptions} from '@tardo/trash';
import type {ProcessCommandJobOptions} from '@tardo/trash/vmachine';

Complete example

The following program declares a TraSH function and delegates the notify command to the JavaScript host. It configures an instruction budget and timer-driven cancellation. Save it as example.mjs and run node example.mjs.

import {
  ARG,
  FUNCTION_TYPE,
  Interpreter,
  VMachine,
} from '@tardo/trash';

const interpreter = new Interpreter();
const vmachine = new VMachine({
  maxInstructions: 100_000,
  maxCollectionLength: 100_000,
  maxStringLength: 1_000_000,
  processCommandJob: async ({cmdName, kwargs}) => {
    if (cmdName !== 'notify') {
      throw new Error(`Unknown host command: ${cmdName}`);
    }
    return `${kwargs.message} (${kwargs.repeat} times)`;
  },
});

vmachine.registerCommand('notify', {
  type: FUNCTION_TYPE.Command,
  args: [
    [ARG.String, ['m', 'message'], true, 'Message to show'],
    [ARG.Number, ['r', 'repeat'], false, 'Number of repetitions', 1],
  ],
});

const source = `
  $total = 0
  for ($value in [1, 2, 3, 4]) {
    $total += $value * $value
  }
  notify -m 'Total of squares: ' + $total -r 2
`;

const program = interpreter.parse(source, {
  registeredCmds: vmachine.getRegisteredCmds(),
});
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 1000);
try {
  const result = await vmachine.execute(program, {signal: controller.signal});
  console.log(result); // Total of squares: 30 (2 times)
} finally {
  clearTimeout(timer);
}

processCommandJob is the boundary between TraSH and the host application. Validate and perform all side effects there, such as database writes, navigation, or API calls.

The default budget is 1,000,000 instructions; this example lowers it to 100,000. Collection and string limits default to 100,000 items and 1,000,000 UTF-16 code units. Cancellation is cooperative: host operations must also honor the signal received by processCommandJob. See the runtime contract for details.

Translations

TraSH has no translation dependency. By default, messages use their English fallback and interpolate {{values}}. Install any translator through setTranslator; for example, setTranslator(i18next.t.bind(i18next)) when using i18next in the host application. Call setTranslator() to restore the default behavior.

import {setTranslator} from '@tardo/trash';

setTranslator((key, fallback, values) => myTranslator.translate(key, {fallback, ...values}));

Basic TraSH usage

$user = {name: 'Ada', scores: [10, 8, 9]}
$total = 0
for ($score in $user['scores']) {
  $total += $score
}

if ($total >= 25) {
  return 'passed: ' + $user['name']
}
return 'pending'
  • Variables begin with $; $name reads a value, including a function. $$name invokes a function; see the compatibility rules for its use in argument position.
  • Calls accept positional arguments, -short arguments, and --long arguments.
  • Wrap a command call that is part of an expression in parentheses.
  • silent command ... returns null if its execution callback throws, unless execution uses throwSilentErrors: true. Argument validation and execution-control errors still propagate; see the error rules.

Plugins

Plugins register internal commands through a small API instead of receiving the runtime. They can define commands, validate arguments with ARG, invoke script callbacks, and validate safe dictionary keys.

import {ARG} from '@tardo/trash/plugin';

const registerDouble = api => {
  api.registerCommand('double', {
    args: [[ARG.Number, ['v', 'value'], true, 'Value to double']],
    callback: async (_context, {value}) => value * 2,
  });
};

vmachine.use(registerDouble);

Deep imports

Deep imports are supported for individual core modules:

import VMachine from '@tardo/trash/vmachine';

Development and contributing

The development setup, testing workflow, style rules, and pull request process are documented in docs/contributing.md.

License

MIT