| .. | ||
| ref-control-freak | ||
| src | ||
| tests | ||
| .gitignore | ||
| .npmignore | ||
| LICENSE | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vitest.config.ts | ||
| webpack.config.js | ||
@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, runRunScriptBlock — Node 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": …, "results": […] } as JSON. |
--loglevel |
info |
debug · info · warn · error |
Blocks file format
Top-level shape (see src/schema/blocks-file.ts):
{
"version": 1,
"context": {},
"roots": [{ "kind": "…", … }, …]
}
context— plain object merged into the executionthis(expressions and scripts usethislike the legacyapply(ctx, args)model).roots— non-empty array of top-level blocks run sequentially, in order (sharedctx), like statements in a script. A UI can map one row per root to a collapsible tree of children.
Block kind values include: if, runScript, for, while, switch, break, wait, plus case / switchDefault inside switch.items.
wait—{ "kind": "wait", "ms": 5000 }pauses for the given milliseconds (async; the executor isasync).
CLI / API output: executeRoots and pm-xblox run return results (one entry per root) and result (last root’s return value).
Legacy note: older UIs often stored a flat array of blocks with id, parentId, declaredClass. This package executes nested trees under each root; you can add an adapter (flat → roots) for editors without changing the executor.
Expressions and scripts
- Conditions and
runScript.methodbodies are evaluated viavm2in@polymech/xblox/runtime, following the samenew 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 |
tsc → dist-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 test:perf |
Runs tests/unit/perf-report.test.ts — prints a console.table of timings. With XBLOX_PERF_REPORT=1, also writes reports/perf-latest.json (gitignored). |
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 and performance helpers (PerfReporter, measureMs, fixture) live in tests/test-commons.ts. Fixtures are in tests/fixtures/.
Performance: import PerfReporter in any test, wrap steps with await perf.measure('label', () => …), then call perf.printSummary() in afterAll. Set XBLOX_PERF_REPORT=1 when running tests to also persist reports/perf-latest.json.
Publishing to npm
package.json→filesis an allowlist: onlydist-in/,README.md, andLICENSEare packed.ref-control-freak/,tests/,src/, webpack/vitest configs, etc. are not published.prepackrunsnpm run build, sodist-in/exists when younpm publishornpm pack.- Dry-run the tarball:
npm pack --dry-run(see “Files included” in the log) ornpm packand inspect the.tgz. dist/(webpack output) is intentionally not infiles; consumers usedist-in/fromtsc.
License
MIT — see LICENSE.