mono/packages/xblox
2026-04-07 19:28:35 +02:00
..
ref-control-freak xblox - port 1/3 2026-02-10 00:02:02 +01:00
src xblox 1/2 2026-04-07 19:28:35 +02:00
tests xblox 1/2 2026-04-07 19:28:35 +02:00
.gitignore xblox 1/2 2026-04-07 19:28:35 +02:00
.npmignore xblox 1/2 2026-04-07 19:28:35 +02:00
LICENSE xblox 1/2 2026-04-07 19:28:35 +02:00
package-lock.json xblox 1/2 2026-04-07 19:28:35 +02:00
package.json xblox 1/2 2026-04-07 19:28:35 +02:00
README.md xblox 1/2 2026-04-07 19:28:35 +02:00
tsconfig.json xblox 1/2 2026-04-07 19:28:35 +02:00
vitest.config.ts xblox 1/2 2026-04-07 19:28:35 +02:00
webpack.config.js xblox 1/2 2026-04-07 19:28:35 +02:00

@polymech/xblox

Block-based control flow for Polymech: if / else-if, for / while, switch / case / default, runScript, and break, with a nested JSON graph format, Zod validation, and a small Node CLI.

This package is a modern take on ideas from the legacy xblox AMD stack (ref-control-freak/ in this repo). It does not reimplement the full legacy Expression.js pipeline ([variables], {block} substitution, block-store UI); it focuses on execution and schema.

Install

From the monorepo, using npm in this package:

cd packages/xblox
npm install
npm run build

Package exports

Import Use
@polymech/xblox Types, enums, ModelBase, RunScriptBlock, engine entrypoints you re-export from app code. No vm2.
@polymech/xblox/runtime runScriptLegacyVm, evalExpression, runRunScriptBlockNode only, uses vm2. Do not import this path in browser bundles if you must avoid vm2.

CLI: pm-xblox

After npm run build, the pm-xblox binary runs validated graphs from disk.

npx pm-xblox run --source=./graph.json
npx pm-xblox run --source=./graph.json --output=./out.json
npx pm-xblox run --source=./graph.json --loglevel=info
Option Default Description
--source (required) Path to a blocks JSON file (version: 1).
--output If set, writes { "result": … } as JSON.
--loglevel info debug · info · warn · error

Blocks file format

Top-level shape (see src/schema/blocks-file.ts):

{
  "version": 1,
  "context": {},
  "root": { "kind": "…",  }
}
  • context — plain object merged into the execution this (expressions and scripts use this like the legacy apply(ctx, args) model).
  • root — a discriminated union on kind: if, runScript, for, while, switch, break, plus case / switchDefault inside switch.items.

Legacy note: older UIs often stored a flat array of blocks with id, parentId, declaredClass. This package currently executes the nested tree; you can add an adapter layer (flat → tree) for editors without changing the executor.

Expressions and scripts

  • Conditions and runScript.method bodies are evaluated via vm2 in @polymech/xblox/runtime, following the same new Function("{ … }").apply(ctx, args) idea as legacy Run Script blocks.
  • This is not a port of legacy Expression.js (no [var] substitution, {block} calls, or expression cache). For full parity with that layer, plan a separate module or bridge.

Security: vm2 is unmaintained; treat user scripts as trusted only in controlled environments, or replace the runtime with a stricter evaluator later.

Development

Script Description
npm run build tscdist-in/
npm run dev tsc --watch
npm run clean Remove dist/ and dist-in/
npm test Run Vitest once
npm run test:watch Vitest watch mode
npm run test:coverage Vitest with V8 coverage
npm run test:ui Vitest browser UI
npm run lint ESLint on src/
npm run webpack After build, emits dist/main_node.js from dist-in/main.js (default package exports only; not @polymech/xblox/runtime / vm2).

Tests live under tests/; shared paths use tests/test-commons.ts. Fixtures are in tests/fixtures/.

Publishing to npm

  • package.jsonfiles is an allowlist: only dist-in/, README.md, and LICENSE are packed. ref-control-freak/, tests/, src/, webpack/vitest configs, etc. are not published.
  • prepack runs npm run build, so dist-in/ exists when you npm publish or npm pack.
  • Dry-run the tarball: npm pack --dry-run (see “Files included” in the log) or npm pack and inspect the .tgz.
  • dist/ (webpack output) is intentionally not in files; consumers use dist-in/ from tsc.

License

MIT — see LICENSE.