diff --git a/.gitattributes b/.gitattributes
index 0871343..16ab2c1 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -17,6 +17,3 @@
*.gif binary
*.woff binary
*.woff2 binary
-
-# Merge strategy for CHANGELOG
-CHANGELOG.md merge=union
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 5546c73..32484d8 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,20 +1,20 @@
-## Related Issues
+## Related issues
Closes #
## Description
-
+
-## Steps to Test
+## How to test
-
+
1.
## Checklist
-- [ ] I have tested this change manually
-- [ ] I have added or updated tests as appropriate
+- [ ] I tested this change by hand
+- [ ] I added or updated tests where needed
- [ ] All checks pass (`npm test`, `npm run lint`, `npm run format:check`, `npm run typecheck --workspaces`)
-- [ ] I have updated documentation as needed
+- [ ] I updated the documentation where needed
diff --git a/.gitignore b/.gitignore
index f7205ec..b8d341c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,7 +42,6 @@ Thumbs.db
# VS Code extension packaging
*.vsix
packages/extension/LICENSE
-packages/extension/CHANGELOG.md
# Environment
.env
@@ -65,3 +64,6 @@ npm-debug.log*
packages/**/test/*.js
packages/**/test/*.js.map
packages/**/test/*.d.ts
+packages/cli/LICENSE
+packages/language/LICENSE
+packages/transform/LICENSE
diff --git a/.nvmrc b/.nvmrc
index 60ade1a..a45fd52 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-24.19.0
+24
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index 204e61e..0000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Changelog
-
-This file follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-
-Nothing has been released yet.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 707ccb5..c3d6ebd 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,19 +1,16 @@
# Contributing to BPMNscript
> This project is being developed as part of a bachelor's thesis.
-> External contributions are not accepted until after thesis submission.
> Bug reports are welcome now.
-> Pull requests are welcome after submission.
-> The guidelines below will apply once the project opens up.
+> Pull requests are accepted after the thesis is submitted, and the guidelines below apply from then on.
## Development setup
### Prerequisites
-- [Node.js](https://nodejs.org/) >= 22 (the project uses Node 24 via `.nvmrc`; [nvm](https://github.com/nvm-sh/nvm)'s `nvm use` reads it)
- `.nvmrc` pins `24.19.0` because 24.20.0 and 24.21.0 fail `langium generate` with `ERR_INVALID_URL`; move it back to `24` once a later 24.x generates cleanly.
-- [VS Code](https://code.visualstudio.com/) with the recommended extensions (VS Code will prompt you on first open)
-- [Docker](https://www.docker.com/) for end-to-end tests (alternatives: [Podman](https://podman.io/), [Rancher Desktop](https://rancherdesktop.io/))
+- [Node.js](https://nodejs.org/) 22 or newer (`.nvmrc` pins Node 24, and `nvm use` reads it)
+- [VS Code](https://code.visualstudio.com/) with the recommended extensions, which VS Code offers on first open
+- [Docker](https://www.docker.com/) for the end-to-end tests ([Podman](https://podman.io/) or [Rancher Desktop](https://rancherdesktop.io/) work too)
### Getting started
@@ -25,9 +22,9 @@ npm run build
npm test
```
-`npm run build` runs the Langium code generator and compiles TypeScript across all packages.
-`npm test` runs the full test suite including Docker-based end-to-end tests.
-To skip those (no Docker installed, or just iterating on unit tests):
+`npm run build` runs the Langium code generator, compiles TypeScript across all packages, and bundles the extension.
+`npm test` runs the full suite, including end-to-end tests that deploy to an Operaton engine in Docker.
+To skip those, for example without Docker or while iterating on unit tests:
```sh
SKIP_DOCKER_TESTS=true npm test
@@ -36,31 +33,21 @@ SKIP_DOCKER_TESTS=true npm test
### Trying it out in VS Code
After building, press F5 in VS Code.
-This opens a second VS Code window with the BPMNscript extension loaded.
-In that window you can create or open `.bpmnscript` files and get syntax highlighting, inline diagnostics, autocompletion, hover, and rename.
-To compile or decompile a file, use the command palette (`BPMNscript: Compile to BPMN` / `BPMNscript: Decompile to BPMNscript`) or the "Convert" panel in the BPMNscript activity-bar sidebar.
-The CLI alternative (`npx bpmns build `) still works if you prefer the terminal.
-For a normal install instead of the development host, see [packages/extension/README.md](packages/extension/README.md#installing).
+A second window opens with the extension loaded, where you can open `.bpmnscript` files and convert them from the command palette or the Convert panel in the BPMNscript sidebar.
+[packages/extension/README.md](packages/extension/README.md) describes what the extension does and how to install it.
### Editing the grammar
-The Langium grammar lives at `packages/language/src/bpmn-script.langium`.
-After editing it, regenerate the AST types before TypeScript can see the changes:
+The Langium grammar is `packages/language/src/bpmn-script.langium`.
+After editing it, regenerate the AST types from the repo root so TypeScript sees the change:
```sh
-npm run langium:generate
+npm run langium:generate # once
+npm run langium:watch # on every save
```
-For continuous regeneration while editing:
-
-```sh
-npm run langium:watch
-```
-
-Both commands run from the repo root.
-
-The generated AST types land under `src/generated/`, which is git-ignored, so there is nothing to commit after regenerating.
-CI's build job still runs `git diff --exit-code` right after `npm run build`; that step fails if the build leaves any tracked file changed, not because of the generated output.
+The generated code lands in `src/generated/`, which is git-ignored, so there is nothing to commit.
+CI runs `git diff --exit-code` after `npm run build` and fails if the build changed any tracked file.
### Running tests
@@ -73,26 +60,49 @@ npm test --workspace packages/extension # E
FUZZ_N=2000 FUZZ_OUT=/tmp/fuzz npm test --workspace tests -- fuzz.test.ts # Round-trip fuzz over 2000 generated programs
```
-`npm test` runs the round-trip fuzz over the first 200 generated programs as part of the tests workspace.
-The extension tests require `@bpmn-script/language` and `@bpmn-script/transform` to be built first (they are consumed as compiled `out/` directories).
-Run `npm run build` from the repo root before running the extension suite in isolation.
+`npm test` includes the round-trip fuzz over the first 200 generated programs.
+The extension tests use the compiled `out/` directories of `@bpmn-script/language` and `@bpmn-script/transform`, so run `npm run build` before running that suite on its own.
### Code style
-The project uses [Prettier](https://prettier.io/) for formatting and [ESLint](https://eslint.org/) (via `eslint-plugin-bpmn-io`) for linting.
-Both run from the repo root:
+[Prettier](https://prettier.io/) formats and [ESLint](https://eslint.org/) lints, both run from the repo root:
```sh
-npm run format # Auto-format all source files
-npm run format:check # Check formatting without writing (used in CI)
-npm run lint # Run ESLint
-npm run typecheck --workspaces # Typecheck test sources; vitest does not (used in CI)
+npm run format # Format all source files
+npm run format:check # Check formatting without writing (CI)
+npm run lint # Run ESLint (does not check formatting)
+npm run typecheck --workspaces # Typecheck the test files, which vitest does not (CI)
+```
+
+VS Code with the recommended Prettier extension formats on save, and `.editorconfig` covers indentation and line endings for other editors.
+
+### Diagnostic messages
+
+Every message a user sees from the compiler, the editor, or the CLI has the same shape.
+
+- The first line is a short headline that says what is wrong and where, and stands on its own.
+ It never says how to fix it.
+- The headline starts in lowercase, unless it opens with a quoted name, and has no final period.
+- Optional lines follow, each starting with `note: ` for context (why it matters, what the engine does) or `help: ` for a concrete fix the user can make.
+ Each line holds one fact, in lowercase after the prefix and without a final period.
+ A line is never a question.
+- No semicolons anywhere in a message, and no "the following" or "as shown".
+- Use plain words that are still technically exact.
+ Name an engine class or method only when it explains the cause, and then in a `note:` line.
+- Put code and names in single quotes.
+
+```
+'emit message Notify' sends nothing without a 'class', 'expression', 'delegate', or 'topic'
+```
+
+```
+the condition must be boolean, but it is a string
+note: the engine throws 'condition expression returns non-Boolean' when it evaluates it
```
-Formatting happens on save if you use VS Code with the recommended Prettier extension.
-The `.editorconfig` handles basics (indentation, line endings) for other editors.
+The language package builds these with `diagnosticText` in `packages/language/src/vocabulary.ts`.
-## Guidelines (post-thesis)
+## Guidelines
### Reporting bugs
@@ -104,12 +114,11 @@ Use the [feature request template](https://github.com/BPMNscript/bpmnscript/issu
### Pull requests
-- Reference the related issue with `Closes #...`
-- Include a brief description of what changed and why
-- Make sure `npm test`, `npm run lint`, `npm run format:check`, and `npm run typecheck --workspaces` all pass
-- Update `CHANGELOG.md` if the change is user-facing
+- Reference the related issue with `Closes #...`.
+- Describe what changed and why.
+- Make sure `npm test`, `npm run lint`, `npm run format:check`, and `npm run typecheck --workspaces` all pass.
### Architectural decisions
-Non-trivial technical decisions are documented as [Markdown ADRs](docs/decisions/) using [MADR 4.0.0](https://adr.github.io/madr/).
-If your change involves an architectural decision, include a new ADR.
+Technical decisions are recorded as [Markdown ADRs](docs/decisions/) using [MADR 4.0.0](https://adr.github.io/madr/).
+If your change makes an architectural decision, add an ADR for it.
diff --git a/README.md b/README.md
index 08442b0..7a0a73d 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,19 @@
# BPMNscript
-Write executable business processes as text, compile to BPMN 2.0 XML, and read existing BPMN files back as text.
+Write executable business processes as text, compile them to BPMN 2.0 XML, and read existing BPMN files back as text.
-> **Status:** a bachelor's thesis project, pre-release.
-> It is not published to npm or the VS Code Marketplace yet, so everything below builds from source.
+> Status: version 0.1.0 is the first release, from a bachelor's thesis project.
+> Download the `.vsix` of the VS Code extension from the GitHub Release, or build everything from source as described below.
+> The packages are not published to npm or the VS Code Marketplace.
## What it is
BPMN 2.0 is the standard for describing a business workflow as a diagram of tasks, gateways, and events.
-A process engine such as [Operaton](https://operaton.org/) loads that diagram and runs it: assigning the human steps to people, calling the automated ones, waiting on timers and incoming messages.
-The diagram is stored as XML, and the XML is what actually gets deployed.
+A process engine such as [Operaton](https://operaton.org/) loads that diagram and runs it: it assigns the human steps to people, calls the automated ones, and waits on timers and incoming messages.
+The diagram is stored as XML, and the XML is what gets deployed.
Usually you draw it in a graphical modeler.
-BPMNscript gives BPMN a textual representation:
+BPMNscript gives BPMN a textual form instead:
```bpmnscript
process invoice-approval {
@@ -31,15 +32,15 @@ process invoice-approval {
}
```
-Compiling this gives you a valid BPMN 2.0 file that a graphical modeler opens as a diagram and Operaton deploys.
+Compiling this gives you a BPMN 2.0 file that a graphical modeler opens as a diagram and Operaton deploys.
## Who it's for
-Developers who'd rather work in a text editor than a diagram canvas, and who want processes to fit into their existing code workflow: git and diffs, autocompletion, and compile-time error checking.
+Developers who'd rather work in a text editor than on a diagram canvas, and who want processes to fit their existing code workflow: git and diffs, autocompletion, and compile-time error checking.
You don't need to know BPMN to read or write BPMNscript.
The keywords say what a step does rather than mirroring the BPMN element behind them.
-The diagram comes for free: describe a valid workflow and the tool draws it, so there are no lines to route, nothing to align, and no redoing a layout because one changed step spoiled it.
+The diagram is generated for you, so there are no lines to route and no layout to redo after a change.
## Installing
@@ -53,30 +54,12 @@ npm run build
```
`npm run build` generates the parser from the grammar, compiles every package, and bundles the VS Code extension.
-
-To check it worked:
-
-```sh
-npm test
-```
-
-The test run includes end-to-end tests that boot a real Operaton engine in Docker via [testcontainers](https://testcontainers.com/), so it needs a running Docker daemon.
-Without one, set `SKIP_DOCKER_TESTS=true` to skip them; CI runs them.
-
-## Documentation
-
-- [packages/language/README.md](packages/language/README.md): the language reference, every statement and the keys it takes
-- [packages/transform/README.md](packages/transform/README.md#the-import-contract): the import contract, what a decompile refuses, drops, or warns about
-- [docs/bpmn-coverage.md](docs/bpmn-coverage.md): the BPMN coverage table, every element kind against the statement that writes it and what the importer does with it
-- [packages/cli/README.md](packages/cli/README.md): the `bpmns` command, its flags and exit codes
-- [packages/extension/README.md](packages/extension/README.md): the VS Code extension, how it is built, installed, and packaged
-- [docs/decisions/](docs/decisions/): the architectural decision records, why things are the way they are
-- [docs/glossary.md](docs/glossary.md): the shared vocabulary
+To check it worked, run `npm test`.
+The suite includes end-to-end tests that boot an Operaton engine in Docker, so it needs a running Docker daemon; set `SKIP_DOCKER_TESTS=true` to skip them ([CONTRIBUTING.md](CONTRIBUTING.md#getting-started)).
## Using the CLI
-The `bpmns` command has two subcommands.
-After a build, run it with `npx`:
+After a build, run the `bpmns` command with `npx`:
```sh
# Compile .bpmnscript to BPMN 2.0 XML, next to the source file
@@ -86,179 +69,57 @@ npx bpmns build examples/spring-boot/processes/invoice-approval.bpmnscript
cd examples/spring-boot/processes
npx bpmns build invoice-approval.bpmnscript -o out/invoice-approval.bpmn
-# Decompile BPMN XML back to the DSL
+# Decompile BPMN XML back to BPMNscript
npx bpmns parse out/invoice-approval.bpmn -o out/invoice-approval.bpmnscript
```
-Exit codes are `0` for success, `1` for validation errors on `build` or a refused BPMN construct on `parse`, and `2` for an I/O problem or input that cannot be read as BPMN XML.
-Both directions print non-fatal warnings to stderr without changing the exit code, so an undeclared variable reference on compile, or a dropped lane on import is warned about but still produces a file.
-`parse` also re-validates the script it wrote and lists every error `build` would draw from it, still with exit `0`.
-Both commands read a file from disk, never stdin, refuse to overwrite an existing output unless you pass `--force`, and refuse the input path itself even then; see [packages/cli/README.md](packages/cli/README.md) for the exact rules.
+Warnings go to stderr and still produce a file.
+A validation error on `build` or a BPMN construct the language can't express on `parse` exits `1` and writes nothing.
+[packages/cli/README.md](packages/cli/README.md) has the exit codes and the rules for overwriting files.
## Using the VS Code extension
Press F5 from the repo root.
VS Code opens a second window with the extension loaded, where `.bpmnscript` files get:
-- syntax highlighting, including inside a `script` task's fenced body, which is highlighted in its own language (JS, Groovy, Python and Ruby; no FEEL grammar is wired in, so it stays plain)
-- completion, hover, go to definition, find all references and rename, for steps, codes and variables, plus an outline, from the same grammar that drives the compiler
-- errors and warnings inline as you type, so a `goto` that can't reach its target, a `string` variable under an ordered comparison, or a `boolean` in arithmetic is flagged before you ever run the compiler
-- a **Convert** panel in the sidebar: compile the open file, jump to its counterpart when one exists, or pick a `.bpmn` from disk to decompile
+- syntax highlighting, including the fenced body of a `script` task in its own language (JavaScript, Groovy, Python and Ruby)
+- completion, hover, go to definition, find all references, rename, and an outline
+- errors and warnings inline as you type, from the same validator `bpmns build` runs
+- a Convert panel in the sidebar that compiles the open file, opens its counterpart when one exists, or decompiles a `.bpmn` picked from disk
-For a normal install instead of the development host, see the extension README's [Installing](packages/extension/README.md#installing) section.
-Compiling and decompiling are the same two operations as `bpmns build` and `bpmns parse` above, without leaving the editor.
-Both are in the command palette too, under "BPMNscript".
-See [packages/extension/README.md](packages/extension/README.md) for how the pieces fit together.
+Compile and decompile are also in the command palette, under "BPMNscript".
+To install the extension for everyday use, see [Installing](packages/extension/README.md#installing) in the extension README.
## The language
-One `process` block per file.
-Steps run top to bottom, so you never write a sequence flow; control flow is expressed with the structured statements you'd expect from a programming language.
-Every step carries an id (`user ReviewInvoice`), which is what `goto` and boundary events refer to.
-A step, a call and a sub-process take their diagram name from that id (`ReviewInvoice` -> "Review Invoice") unless a `label` setting gives one instead; a `start` and an `end` are named by `label` alone, and their id is never humanized into a name.
-The event statements `on`, `throw`, `emit` and `await` are the exception: their id is a jump target only, so they take no `label` and show no name at all, except on the two ends of a link pair, which carry their link name.
+A file holds one `process` block.
+Steps run top to bottom, so you never write a sequence flow; control flow uses structured statements (`if`, `while`, `parallel`, `goto`), and events read like try/catch with `on`, `throw` and `emit`.
+The [language reference](packages/language/README.md) lists every statement, the BPMN element it compiles to, and the settings it takes.
-The [statement table](packages/language/README.md#statements) lists every statement, what it means, and the BPMN element it compiles to.
-The same page gives the keys each element takes, which elements take parameters and listeners, and what a conditioned `parallel` branch compiles to.
+[examples/spring-boot/processes/](examples/spring-boot/processes/) holds the example processes, each covering one construct or combination; [examples/README.md](examples/README.md) says which.
-The `attempt` head and the `cancel` end are one construct: the end gives up the block it sits in, `on : cancel` beside the block catches it, and the block's finished steps that carry an `on compensation` block (the undo block) are undone in between.
+## Round-tripping BPMN XML to BPMNscript
-### Events
+BPMN is a much larger language than BPMNscript, so a `.bpmn` file can hold more than a script has a form for.
+A decompile never changes a process without saying so ([ADR-0012](docs/decisions/0012-honest-bpmn-import.md)):
-The event layer reads like try/catch.
-A handler written at the end of a body catches an event raised anywhere inside it, `throw` ends the current path the way `throw` does in Java, and `emit` fires the event and carries on.
-`emit link` is the one emit that ends the path instead: the token continues at the `await link` of the same name, which is how a diagram's off-page connector reads ([packages/language/README.md](packages/language/README.md#link-events)).
-Every trigger kind but `cancel` and `link` opens such a handler, `cancel` being caught on the block it gives up and `link` by its `await`; the table in [packages/language/README.md](packages/language/README.md#the-event-layer) gives each kind with its payload.
-A message, a signal, a timer, or a condition can also start a process, carrying the same payload it does as a handler, and a `terminate` end stops every running path at once.
-An error or escalation code is declared in the process header, beside the `var` declarations, and named at every throw, emit, and catch site, and in an external task's `error when ` mapping.
+- A construct the language can't express, or one Operaton refuses to deploy, is refused with an error and nothing is written.
+- Content BPMNscript doesn't carry, such as a lane, a pool or a text annotation, is dropped with a warning naming each item.
+- A construct imported in a changed form gets a warning that says whether the engine runs it differently.
+- A part of the graph the printer can't fit into a block becomes a `goto`, or a `// unstructured region: hand-repair required` comment where no jump fits, and is warned about.
-A handler can also attach to one step instead of the whole body, which is where `on Host: kind` comes in.
-This process reviews an order, takes payment in a sub-process, and hangs four different escapes off those two activities:
-
-```bpmnscript
-process order-handling {
- error PAYMENT_DECLINED(message: "The card could not be charged")
- escalation LARGE_PAYMENT_FLAGGED
-
- start OrderPlaced
- user ReviewOrder(label: "Review order", assignee: "demo")
-
- subprocess Payment(label: "Process payment") {
- service AuthorizePayment(label: "Authorize payment", class: "com.example.demo.LogDelegate")
- emit escalation(LARGE_PAYMENT_FLAGGED)
- service CapturePayment(label: "Capture payment", class: "com.example.demo.LogDelegate")
- }
-
- service ShipOrder(label: "Ship order", class: "com.example.demo.LogDelegate")
- end OrderShipped
-
- on ReviewOrder: timer("PT4H", alongside) {
- service SendReviewReminder(label: "Send a review reminder", class: "com.example.demo.LogDelegate")
- }
-
- on ReviewOrder: message("AutoApproved") {
- service MarkAutoApproved(label: "Mark the order auto-approved", class: "com.example.demo.LogDelegate")
- goto Payment
- }
-
- on Payment: error(PAYMENT_DECLINED, code: c, message: m) {
- user ContactCustomer(label: "Contact the customer about the decline", assignee: "demo")
- }
-
- on Payment: escalation(LARGE_PAYMENT_FLAGGED, alongside) {
- user ReviewLargePayment(label: "Review the large payment", assignee: "manager")
- }
-}
-```
-
-`alongside` is the difference between interrupting the step and running beside it.
-The four-hour timer nudges the reviewer while review stays open; the `AutoApproved` message cancels the review outright and jumps to payment.
-The declined-card error kills the payment sub-process and hands the customer to an agent, and the large-payment escalation pulls in a manager without stopping the capture.
-
-### Compensation
-
-A `subprocess` can carry an `on compensation` block: the steps that undo whatever it already did.
-When something later fails, the completed units unwind newest first.
-
-```bpmnscript
-process booking-saga {
- error BOOKING_FAILED(message: "A booking step could not be completed")
-
- start TripRequested
- user ReviewTrip(label: "Review the trip", assignee: "demo")
-
- subprocess BookFlight(label: "Book the flight") {
- service ReserveSeat(label: "Reserve the seat", class: "com.example.demo.LogDelegate")
-
- on compensation {
- service ReleaseSeat(label: "Release the seat", class: "com.example.demo.LogDelegate")
- }
- }
-
- subprocess BookHotel(label: "Book the hotel") {
- service ReserveRoom(label: "Reserve the room", class: "com.example.demo.LogDelegate")
-
- on compensation {
- service ReleaseRoom(label: "Release the room", class: "com.example.demo.LogDelegate")
- }
- }
-
- service ConfirmTrip(label: "Confirm the trip", class: "com.example.demo.LogDelegate")
- end TripConfirmed
-
- on error(BOOKING_FAILED) {
- emit compensation Undo
- user NotifyTraveler(label: "Notify the traveler", assignee: "demo")
- }
-}
-```
-
-Book the hotel after the flight, then fail: the seat gets released, and the traveler gets told.
-
-The invoice-approval and order-handling programs above are files from [examples/spring-boot/processes/](examples/spring-boot/processes/), the second with one boundary handler left out; the compensation one is written for this page, and `compensating-saga.bpmnscript` is its deployable counterpart.
-The end-to-end suite deploys several of that directory's processes to an Operaton engine and asserts what the engine does with them.
-
-## Roundtripping BPMN XML -> BPMNscript
-
-BPMN is a much larger language than this DSL, so a `.bpmn` file can hold more than a `.bpmnscript` has a form for.
-A decompile deals with that in three ways.
-
-- A construct the DSL cannot express (an ad hoc subprocess, a compensation boundary event, an event definition the language doesn't model) is refused with an error and nothing is written, and so is a shape Operaton refuses to deploy, such as an exclusive gateway with two unconditioned routes or an `operaton:inputOutput` on a gateway.
-- Content the intermediate representation doesn't carry (a pool, a lane, a text annotation, a listener found on a gateway, a manual task, a standard loop, a data object) is dropped with a warning naming each item, and so is an `isExecutable="false"`, which imports as executable whatever the source said.
- The exceptions are attributes the importer doesn't read.
-- What the print hop cannot carry into the script is warned about too, and those warnings are the ones to read before building the output.
- A gateway's name merely drops, since the script derives its splits and merges from block structure and no statement is left to carry one.
- A fork whose branches all carry conditions and that named no fallback changes what a recompiled document runs, because the printed block falls through where the model stops with a stuck execution.
- A route with no `goto` target to jump to is left out entirely, replaced by a `// unstructured region: hand-repair required` comment naming the element it led into.
- An `else` beside a branch that runs whatever the conditions do prints a fallback nothing can reach, and the validator then rejects the script `bpmns parse` just wrote.
- An id the script cannot spell is respelled and the change is reported, since the engine keys history, a migration plan and a start-before-activity on that id, so a rebuilt document does not run as the same process.
- A jump into a step reached from outside the `await` or `parallel` branch it printed in is still written and reported, and the validator then refuses it once `bpmns parse` reads the script back, because a branch's steps run only when the whole block is reached.
- A split or wait left with no route out is dropped from the script outright, and the warning names what the engine does in its place, from ending the run the same way to refusing to deploy the model at all.
-
-A branch that only rejoins the block's tail may print after the block instead, reached by a `goto`, and the block's join may be replaced by direct edges into that tail; the set of steps and their order along each path is unchanged, so this restructuring prints with no warning at all.
-
-What each hop reports, item by item, is the import contract in [packages/transform/README.md](packages/transform/README.md#the-import-contract) and the print warnings in [packages/transform/README.md](packages/transform/README.md#print-warnings).
-[ADR-0014](docs/decisions/0014-restructure-the-ir-into-a-dsl-with-dominator-analysis.md) covers which shapes degrade and why.
-
-Every engine setting a modeler tunes imports warning-free; the IR shape in [packages/transform/README.md](packages/transform/README.md#ir-shape) lists each one.
-A user task assigned in BPMN's own words, a `bpmn:humanPerformer` or a `bpmn:potentialOwner`, imports onto the same `assignee`, `candidateUsers` and `candidateGroups` the engine reads it into, with a warning naming the rewrite ([ADR-0012](docs/decisions/0012-honest-bpmn-import.md)).
-A link throw is one exception: each engine setting and listener on one warns, because Operaton creates no activity for a link throw and so never reads them ([ADR-0030](docs/decisions/0030-link-events-for-import-round-trip-symmetry.md)).
-`asyncAfter` on an event-based gateway is the other: the import refuses it, as Operaton refuses to deploy it ([ADR-0021](docs/decisions/0021-operaton-engine-attributes-as-named-ir-fields.md)).
-What stays out of reach is a setting with nowhere to sit in the text.
-That is a listener or an input/output parameter on a synthesized gateway, a setting on the `bpmn:process` element, or a job priority on the repetition element, which the engine reads off the step alone.
-
-The reasoning is in [ADR-0012](docs/decisions/0012-honest-bpmn-import.md).
-The short version: a round trip that changes the model/workflow without warning is worse than one that refuses to run.
+Engine settings a modeler tunes on a step, such as async continuations, listeners, input/output parameters and forms, import without a warning.
+The diagram's coordinates are discarded, since the layout is generated again on every compile.
+[packages/transform/README.md](packages/transform/README.md#the-import-contract) lists every refusal and warning, and [docs/bpmn-coverage.md](docs/bpmn-coverage.md) shows what happens to each BPMN element.
## Running a process on a real engine
-[examples/spring-boot/](examples/spring-boot/) is a working Operaton 2.1.0 + Spring Boot deployment with Java delegates for the service tasks.
-Its [README](examples/spring-boot/README.md) walks through compiling the processes, starting the engine, opening Cockpit and Tasklist, and stepping through a loan approval example process by hand.
+[examples/spring-boot/](examples/spring-boot/) is an Operaton 2.1.0 and Spring Boot deployment with Java delegates for the service tasks.
+Its [README](examples/spring-boot/README.md) walks through compiling the processes, starting the engine, and stepping through a loan approval in Cockpit and Tasklist.
## Architecture
-Both directions route through a shared intermediate representation.
-Each transform only has to know how to convert to or from the IR, never to every other format directly.
+Both directions go through a shared intermediate representation (IR), so each transform converts to or from the IR and never directly between file formats.
```mermaid
flowchart LR
@@ -274,54 +135,52 @@ flowchart LR
IR -- irToDsl --> SRC
```
-A source file is parsed into an AST, converted into the IR (a small set of plain TypeScript objects in `packages/transform/src/ir/types.ts` that describe a process in the engine's own terms, tied to no file format), and written out from there.
-Compiling is `.bpmnscript` -> AST -> IR -> `.bpmn`; decompiling is `.bpmn` -> IR -> `.bpmnscript`.
-
-The IR carries Operaton's semantics under names with no vendor prefix: the engine's bindings, execution settings, input/output parameters and lifecycle listeners are all plain-named IR fields, and `operaton:` is applied only where `irToXml` builds the moddle element from a local [moddle extension](packages/transform/src/operaton-moddle.json) ([ADR-0007](docs/decisions/0007-intermediate-representation-ast-bpmn.md), [ADR-0021](docs/decisions/0021-operaton-engine-attributes-as-named-ir-fields.md), [ADR-0020](docs/decisions/0020-listeners-reuse-on-inside-the-attribute-block.md)).
+The IR is a small set of plain TypeScript objects that describe one process in the engine's terms, tied to no file format ([ADR-0007](docs/decisions/0007-intermediate-representation-ast-bpmn.md)).
+[packages/transform/README.md](packages/transform/README.md) describes it and the four transforms.
-| Library | Role |
-| --------------------------------------------------------------- | --------------------------------------------------- |
-| [Langium](https://langium.org/) | Grammar, parser, AST, LSP server, VS Code extension |
-| [bpmn-moddle](https://github.com/bpmn-io/bpmn-moddle) | BPMN 2.0 XML reading and writing |
-| [bpmn-auto-layout](https://github.com/bpmn-io/bpmn-auto-layout) | Generates diagram layout data on export |
+| Library | Role |
+| --------------------------------------------------------------- | --------------------------------------- |
+| [Langium](https://langium.org/) | Grammar, parser, AST, LSP server |
+| [bpmn-moddle](https://github.com/bpmn-io/bpmn-moddle) | BPMN 2.0 XML reading and writing |
+| [bpmn-auto-layout](https://github.com/bpmn-io/bpmn-auto-layout) | Generates diagram layout data on export |
## Repository structure
```text
packages/
language/ Langium grammar, AST, validator, language server
- transform/ IR types and bidirectional transforms (AST/IR/XML/DSL)
+ transform/ IR types and the four transforms (AST/IR/XML/DSL)
cli/ bpmns build / parse commands
- extension/ VS Code extension: language server, compile/decompile commands, sidebar
+ extension/ VS Code extension: language server, conversion commands, sidebar
tests/ Round-trip, fixture, and end-to-end tests
examples/
spring-boot/ Operaton + Spring Boot deployment, also the e2e fixture
docs/
- decisions/ Architectural decision records
- glossary.md Shared vocabulary
+ decisions/ Architectural decision records
+ bpmn-coverage.md BPMN elements and what happens to each
+ glossary.md Shared vocabulary
```
## Limitations
-The tool writes one executable process per file: a collaboration with pools and message flows imports as that one process, with a warning per pool and per message flow, and a second executable process refuses the import ([coverage table](docs/bpmn-coverage.md#collaboration-and-root-elements)).
-Lanes have no textual form, so a lane is dropped with a warning and every step lands in the one process ([coverage table](docs/bpmn-coverage.md#collaboration-and-root-elements)).
-Data objects, data stores, and data associations are not authored and are dropped with a warning on import; a process variable is declared with `var` and reaches a step through `input` and `output` parameters instead ([coverage table](docs/bpmn-coverage.md#data)).
-Text annotations, associations, and groups go the same way ([coverage table](docs/bpmn-coverage.md#artifacts-and-diagram)).
-An ad hoc sub-process and a complex gateway have no statement, so either refuses the import ([activities](docs/bpmn-coverage.md#activities), [gateways](docs/bpmn-coverage.md#gateways)).
-A standard loop is dropped with a warning: the activity that carried it still imports, but runs once regardless ([coverage table](docs/bpmn-coverage.md#activities)).
-A manual task and a definition-less intermediate throw are not authored; each imports as a plain `step` instead, with a warning naming the rewrite ([activities](docs/bpmn-coverage.md#activities), [intermediate throw events](docs/bpmn-coverage.md#intermediate-throw-events)).
-A compensation handler is written on a `subprocess` only, so BPMN's compensation boundary event with its association refuses the import and the message names the rewrite ([coverage table](docs/bpmn-coverage.md#boundary-events)).
-Forms are the `operaton:formData` fields on a start or a user task, or a `formKey`/`formRef` naming one deployed elsewhere; a form field typed outside `string`, `long`, `boolean`, `date`, and `enum` refuses the import ([import contract](packages/transform/README.md#refusals)).
-A `decide` step names a deployed decision table, and the language has no form for the table itself ([packages/language/README.md](packages/language/README.md#send-receive-and-decision-tasks)).
-The diagram is generated on every compile, so hand-placed coordinates in a `.bpmn` file are discarded on import without a warning ([ADR-0009](docs/decisions/0009-auto-layout-and-expansion-hint.md)).
+- One executable process per file.
+ A collaboration imports as its one executable process, with a warning per pool and per message flow, and a second executable process refuses the import.
+- Lanes, data objects, data stores, text annotations and groups have no textual form and are dropped with a warning.
+ Process variables are declared with `var` and reach a step through `input` and `output` parameters.
+- An ad hoc sub-process and a complex gateway refuse the import.
+- A standard loop is dropped with a warning, so the activity runs once.
+- A compensation handler is written as an undo block inside a `subprocess`, so a compensation boundary event refuses the import and the message names the rewrite.
+- A `decide` step names a deployed decision table; the table itself is written outside BPMNscript.
+- Hand-placed diagram coordinates are discarded on import without a warning ([ADR-0009](docs/decisions/0009-auto-layout-and-expansion-hint.md)).
+
+[docs/bpmn-coverage.md](docs/bpmn-coverage.md) has the full list.
## Project status
BPMNscript is being built as a bachelor's thesis at [University of Hamburg](https://www.uni-hamburg.de/), supervised by Dr. Oliver Kopp.
The thesis asks whether a textual DSL can be a practical alternative to graphical BPMN editors for developers who prefer working in code.
-Design decisions are written up as [Markdown ADRs](docs/decisions/) using [MADR 4.0.0](https://adr.github.io/madr/); they're the best place to find out why something is the way it is.
-Shared vocabulary is collected in [docs/glossary.md](docs/glossary.md).
+Design decisions are written up as [Markdown ADRs](docs/decisions/) using [MADR 4.0.0](https://adr.github.io/madr/), and terms are collected in the [glossary](docs/glossary.md).
## Contributing
diff --git a/docs/bpmn-coverage.md b/docs/bpmn-coverage.md
index 387c992..130e5d9 100644
--- a/docs/bpmn-coverage.md
+++ b/docs/bpmn-coverage.md
@@ -4,29 +4,31 @@ Which BPMN 2.0 elements BPMNscript writes, and what the importer does with each
The BPMNscript column is the statement that compiles to the element, or "not authored" when the language has no form for it; the statement's keys are in [packages/language/README.md](../packages/language/README.md).
The import column says whether `xmlToIr` imports the element, imports it changed or drops it with a warning (the category in parentheses), or refuses the file (the error class in parentheses); the exact conditions are in the [import contract](../packages/transform/README.md#the-import-contract).
Operaton's own extension elements (`operaton:` settings, input/output parameters, listeners, form fields) are not BPMN elements and are listed with the [IR shape](../packages/transform/README.md#ir-shape) instead.
+An element's `id` is its name in the script, written plainly where the `ID` terminal spells it and in backticks otherwise (`` user `Task.1` ``), so every id a name slot carries survives import and rebuild ([ADR-0010](decisions/0010-deterministic-synthesized-ids.md)).
+A file holding an id outside ASCII letters, digits, `_`, `-` and `.`, starting with a letter or `_`, is refused (`UnsupportedDocumentError`).
## Activities
-| BPMN element | BPMNscript | Import |
-| ------------------------------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `bpmn:task` | `step X` | imported |
-| `bpmn:manualTask` | not authored | imported as `step`, warned (`rewritten`): history reports `task` where the source wrote `manualTask` |
-| `bpmn:userTask` | `user X(...)` | imported; refused on a `bpmn:humanPerformer` beside `operaton:assignee` or a second `bpmn:humanPerformer` (`UnsupportedAssignmentError`) |
-| `bpmn:humanPerformer`, `bpmn:potentialOwner` on a user task | `assignee`, `candidateUsers`, `candidateGroups` keys | imported onto those keys, warned (`rewritten`) naming the rewrite |
-| `bpmn:performer`, `bpmn:resourceRole`, a role on any other activity | not authored | dropped, warned (`unmappedConstruct`) |
-| `bpmn:serviceTask` | `service X(...)` | imported; refused without a binding the engine reaches, with a `type` outside `external`, `mail`, and `shell`, or with an `operaton:connector` (`UnsupportedServiceTaskFormError`) |
-| `bpmn:sendTask` | `send X(...)` | imported, refused as a service task is |
-| `bpmn:businessRuleTask` | `decide X(...)` | imported, refused as a service task is, plus on a `decisionRefTenantId` or a `decisionRefBinding` of `versionTag` (`UnsupportedServiceTaskFormError`) |
-| `bpmn:receiveTask` | `receive X(...)` | imported |
-| `bpmn:scriptTask` | `script X` with a fenced body | imported; refused on an empty `scriptFormat`, on neither a body nor a resource, or on a `operaton:resource` in place of the body (`UnsupportedExtensionFormError`) |
-| `bpmn:callActivity` | `call X(process: "...")` | imported; refused on a `caseRef`, a `calledElementTenantId`, a `versionTag` binding, or an `in`/`out` mapping outside the recognized shapes (`UnsupportedCallActivityError`) |
-| `bpmn:subProcess` | `subprocess X { }` | imported; refused without a start event (`UnsupportedEventFeatureError`) |
-| `bpmn:subProcess` with `triggeredByEvent="true"` | `on { }` | imported as an event handler, see the start event rows |
-| `bpmn:transaction` | `attempt X { }` | imported, a missing start event added, warned (`behaviourChanged`); `method`, `protocol`, and `triggeredByEvent` dropped, warned (`unmappedConstruct`) |
-| `bpmn:adHocSubProcess` | not authored | refused (`UnsupportedElementError`) |
-| `bpmn:multiInstanceLoopCharacteristics` | `for each x in c`, `for 3`, with `sequentially` | imported; refused on an event handler, beside an `operaton:outputParameter`, or with a `loopCardinality` body the script cannot spell (`UnsupportedLoopCharacteristicsError`) |
-| `bpmn:standardLoopCharacteristics` | not authored | dropped, warned (`unmappedConstruct`): Operaton runs the activity once regardless |
-| `startQuantity`, `completionQuantity` other than `1` | not authored | dropped, warned (`unmappedConstruct`): Operaton never reads either |
+| BPMN element | BPMNscript | Import |
+| ------------------------------------------------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `bpmn:task` | `step X` | imported |
+| `bpmn:manualTask` | not authored | imported as `step`, warned (`rewritten`): history reports `task` where the source wrote `manualTask` |
+| `bpmn:userTask` | `user X(...)` | imported; refused on a `bpmn:humanPerformer` beside `operaton:assignee` or a second `bpmn:humanPerformer` (`UnsupportedAssignmentError`) |
+| `bpmn:humanPerformer`, `bpmn:potentialOwner` on a user task | `assignee`, `candidateUsers`, `candidateGroups` keys | imported onto those keys, warned (`rewritten`) naming the rewrite |
+| `bpmn:performer`, `bpmn:resourceRole`, a role on any other activity | not authored | dropped, warned (`unmappedConstruct`) |
+| `bpmn:serviceTask` | `service X(...)` | imported; refused without a binding the engine reaches, with a `type` outside `external`, `mail`, and `shell`, or with an `operaton:connector` (`UnsupportedServiceTaskFormError`) |
+| `bpmn:sendTask` | `send X(...)` | imported, refused as a service task is |
+| `bpmn:businessRuleTask` | `decide X(...)` | imported, refused as a service task is, plus on a `decisionRefTenantId` or a `decisionRefBinding` of `versionTag` (`UnsupportedServiceTaskFormError`) |
+| `bpmn:receiveTask` | `receive X(...)` | imported |
+| `bpmn:scriptTask` | `script X` with a fenced body | imported; refused on an empty `scriptFormat`, on neither a body nor a resource, or on an `operaton:resource` in place of the body (`UnsupportedExtensionFormError`) |
+| `bpmn:callActivity` | `call X(process: "...")` | imported; refused on a `caseRef`, a `calledElementTenantId`, a `versionTag` binding, or an `in`/`out` mapping outside the recognized shapes (`UnsupportedCallActivityError`), or a mapping whose `source` or `target` names a variable no plain name spells, such as `var` (`UnsupportedVariableNameError`) |
+| `bpmn:subProcess` | `subprocess X { }` | imported; refused without a start event (`UnsupportedEventFeatureError`) |
+| `bpmn:subProcess` with `triggeredByEvent="true"` | `on { }` | imported as an event handler, see the start event rows |
+| `bpmn:transaction` | `attempt X { }` | imported, a missing start event added, warned (`behaviourChanged`); `method`, `protocol`, and `triggeredByEvent` dropped, warned (`unmappedConstruct`) |
+| `bpmn:adHocSubProcess` | not authored | refused (`UnsupportedElementError`) |
+| `bpmn:multiInstanceLoopCharacteristics` | `for each x in c`, `for 3`, with `sequentially` | imported; refused on an event handler, beside an `operaton:outputParameter`, or with a `loopCardinality` body the script cannot spell (`UnsupportedLoopCharacteristicsError`) |
+| `bpmn:standardLoopCharacteristics` | not authored | dropped, warned (`unmappedConstruct`): Operaton runs the activity once regardless |
+| `startQuantity`, `completionQuantity` other than `1` | not authored | dropped, warned (`unmappedConstruct`): Operaton never reads either |
## Gateways
@@ -118,6 +120,7 @@ Operaton's own extension elements (`operaton:` settings, input/output parameters
| `bpmn:conditionExpression`, and a conditional event definition's `bpmn:condition` | the condition of `if`, `while`, `do ... while`, a `parallel` branch, and of `condition(expr)` | imported; refused with a `language` attribute or an `xsi:type` other than `tFormalExpression` (`UnsupportedConditionExpressionError`) |
| `default` on a gateway | `else`, the fallback branch | imported as written (`mapDefaultingGateway`); on an exclusive gateway the shape check above can still refuse the gateway around it |
| `default` on an activity | `else`, the fallback branch | imported when it names one of the activity's own outgoing flows; dropped, warned (`unmappedConstruct`) otherwise |
+| no `default` where every route out is conditioned | `else fail`, closing the `if` chain or the `parallel` block | imported; prints as `else fail`, so the engine still stops the run when no condition holds |
| `name` on a sequence flow | not authored, derived from the condition | warned (`label`) when it differs from the derived label |
| a flow into or out of an event sub-process | not authored | refused, `BpmnParse.parseSequenceFlow` fails on it (`UnsupportedEventFeatureError`) |
@@ -133,25 +136,25 @@ Operaton's own extension elements (`operaton:` settings, input/output parameters
## Collaboration and root elements
-| BPMN element | BPMNscript | Import |
-| ---------------------------------------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `bpmn:process`, one marked `isExecutable="true"` | `process X { }`, one per file | imported |
-| a second executable `bpmn:process` | not authored | refused (`UnsupportedCollaborationError`) |
-| a `bpmn:process` not marked executable beside the executable one | not authored | dropped, warned (`unmappedConstruct`) |
-| a lone `bpmn:process` not marked executable | `process X { }` | imported as an executable process, warned (`behaviourChanged`) |
-| several `bpmn:process` elements, none marked executable | not authored | refused (`UnsupportedDocumentError`) |
-| `bpmn:collaboration`, `bpmn:participant` | not authored | dropped, warned (`unmappedConstruct`), one warning per pool |
-| `bpmn:messageFlow` | not authored | dropped, warned (`unmappedConstruct`), one warning per flow |
-| `bpmn:laneSet`, `bpmn:lane` | not authored | dropped, warned (`lane`), one warning per lane |
-| `bpmn:error`, `bpmn:escalation` | `error CODE(message: "...")`, `escalation CODE` in the process header | imported as declarations; refused on an error root with an `operaton:errorMessage` and no code, or two roots sharing a code with two messages (`UnsupportedEventFeatureError`); a root with no code warned (`unreferencedRoot`) |
-| `bpmn:message`, `bpmn:signal` | synthesized from the names the events use | imported by reference; one nothing references warned (`unreferencedRoot`); two signals sharing a name refused (`UnsupportedEventFeatureError`) |
-| `bpmn:category`, `bpmn:interface`, any other root | not authored | dropped, warned (`unmappedConstruct`) |
-| `bpmn:import` | not authored | refused (`UnsupportedDocumentError`) |
+| BPMN element | BPMNscript | Import |
+| ---------------------------------------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `bpmn:process`, one marked `isExecutable="true"` | `process X { }`, one per file | imported |
+| a second executable `bpmn:process` | not authored | refused (`UnsupportedCollaborationError`) |
+| a `bpmn:process` not marked executable beside the executable one | not authored | dropped, warned (`unmappedConstruct`) |
+| a lone `bpmn:process` not marked executable | `process X { }` | imported as an executable process, warned (`behaviourChanged`) |
+| several `bpmn:process` elements, none marked executable | not authored | refused (`UnsupportedDocumentError`) |
+| `bpmn:collaboration`, `bpmn:participant` | not authored | dropped, warned (`unmappedConstruct`), one warning per pool |
+| `bpmn:messageFlow` | not authored | dropped, warned (`unmappedConstruct`), one warning per flow |
+| `bpmn:laneSet`, `bpmn:lane` | not authored | dropped, warned (`lane`), one warning per lane |
+| `bpmn:error`, `bpmn:escalation` | `error CODE(message: "...")`, `escalation CODE` in the process header | imported as declarations under the root's `name`; refused on an error root with an `operaton:errorMessage` and no code, or two roots sharing a code with two messages (`UnsupportedEventFeatureError`); a root with no code warned (`unreferencedRoot`) |
+| `bpmn:message`, `bpmn:signal` | synthesized from the names the events use | imported by reference; one nothing references warned (`unreferencedRoot`); two signals sharing a name refused (`UnsupportedEventFeatureError`) |
+| `bpmn:category`, `bpmn:interface`, any other root | not authored | dropped, warned (`unmappedConstruct`) |
+| `bpmn:import` | not authored | refused (`UnsupportedDocumentError`) |
## Artifacts and diagram
-| BPMN element | BPMNscript | Import |
-| ------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
-| `bpmn:textAnnotation`, `bpmn:association`, `bpmn:group` | not authored | dropped, warned (`unmappedConstruct`) |
-| `bpmn:documentation` | `documentation: "..."` on the process and on a step | imported at every position that reads a `name`; warned (`documentation`) on an event handler, a typed event, a sequence flow, and the roots |
-| `bpmndi:BPMNDiagram` and everything under it | not authored, generated by auto-layout on compile | discarded without a warning |
+| BPMN element | BPMNscript | Import |
+| ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `bpmn:textAnnotation`, `bpmn:association`, `bpmn:group` | not authored | dropped, warned (`unmappedConstruct`) |
+| `bpmn:documentation` | `documentation: "..."` on the process and on a step, and `conditionDocumentation`, `timerDocumentation`, `countDocumentation` or `eachDocumentation` beside the value it documents | imported at every position that reads a `name`, inside a condition, a time, a repetition count, a completion condition, and a named `bpmn:inputDataItem`; warned (`documentation`) on an event handler, a typed event, a sequence flow, an event definition, a repetition, an unnamed `bpmn:inputDataItem`, and the roots |
+| `bpmndi:BPMNDiagram` and everything under it | not authored, generated by auto-layout on compile | discarded without a warning |
diff --git a/docs/decisions/0001-use-apache-2-license.md b/docs/decisions/0001-use-apache-2-license.md
index 4d57583..6533eb5 100644
--- a/docs/decisions/0001-use-apache-2-license.md
+++ b/docs/decisions/0001-use-apache-2-license.md
@@ -4,7 +4,7 @@ date: 2026-04-13
decision-makers: Marlon Kranz
---
-# Use Apache 2.0 License
+# Use the Apache 2.0 license
## Context and Problem Statement
@@ -32,4 +32,4 @@ It is compatible with both MIT and EPL-2.0 dependencies.
- Good, because Apache 2.0 includes an explicit patent grant, protecting contributors and users
- Good, because it is compatible with the licenses of all key dependencies
-- Neutral, because Apache 2.0 requires a NOTICE file for derivative works, adding slight administrative overhead
+- Neutral, because Apache 2.0 section 4(d) requires redistributors to keep a NOTICE file only if the work includes one, and this project ships none
diff --git a/docs/decisions/0002-use-mono-repo-structure.md b/docs/decisions/0002-use-mono-repo-structure.md
index 6f4233d..76fa183 100644
--- a/docs/decisions/0002-use-mono-repo-structure.md
+++ b/docs/decisions/0002-use-mono-repo-structure.md
@@ -4,11 +4,11 @@ date: 2026-04-13
decision-makers: Marlon Kranz
---
-# Use Mono-repo Structure
+# Use a mono-repo structure
## Context and Problem Statement
-BPMNscript consists of multiple components: the core language (grammar, parser, AST, validation), a CLI tool, and a VS Code extension.
+BPMNscript consists of multiple components: the core language (grammar, parser, AST, validation), the transform between the language and BPMN XML, a CLI tool, and a VS Code extension.
Should these components live in a single repository or be split across multiple repositories?
## Decision Drivers
@@ -20,7 +20,7 @@ Should these components live in a single repository or be split across multiple
## Considered Options
- Mono-repo with npm workspaces
-- Multi-repo (separate repos for core, CLI, VS Code extension)
+- Multi-repo (separate repos for the language, the transform, the CLI and the VS Code extension)
## Decision Outcome
diff --git a/docs/decisions/0003-use-langium-as-language-workbench.md b/docs/decisions/0003-use-langium-as-language-workbench.md
index 02294a0..243868e 100644
--- a/docs/decisions/0003-use-langium-as-language-workbench.md
+++ b/docs/decisions/0003-use-langium-as-language-workbench.md
@@ -4,7 +4,7 @@ date: 2026-04-13
decision-makers: Marlon Kranz
---
-# Use Langium as Language Workbench
+# Use Langium as the language workbench
## Context and Problem Statement
@@ -31,7 +31,7 @@ Which language workbench should be used to implement the DSL infrastructure?
## Decision Outcome
-Chosen option: "Langium", primarily for its own ergonomics: a smaller, more approachable toolchain than Xtext's, and native access to the existing TypeScript BPMN tooling this project builds on: `bpmn-moddle` to read and write BPMN 2.0 XML, and `bpmn-auto-layout` to generate the Diagram Interchange (DI) data a textual syntax has no coordinate system to produce by hand.
+Chosen option: "Langium", primarily for its own ergonomics: a smaller, more approachable toolchain than Xtext's, and native access to the existing JavaScript BPMN tooling this project builds on: `bpmn-moddle` to read and write BPMN 2.0 XML, and `bpmn-auto-layout` to generate the Diagram Interchange (DI) data a textual syntax has no coordinate system to produce by hand.
The IDE target followed from this choice rather than preceding it: `langium-cli` generates the AST types and a TextMate grammar from the grammar, the language server builds its parser, completion, scoping and validation on the same grammar at run time, and a one-time project template supplies the VS Code extension that hosts the server.
That made Visual Studio Code the easier of the two viable targets to reach, whereas an IntelliJ plugin for Xtext would not have benefited from the same path.
Browser deployment for a future playground was a secondary factor, all within a timeline-feasible learning curve.
@@ -41,7 +41,7 @@ Browser deployment for a future playground was a secondary factor, all within a
- Good, because the entire stack is TypeScript, eliminating context-switching between languages
- Good, because the grammar yields the AST types and syntax highlighting at build time, and the parser, completion, go-to-definition, and diagnostics at run time
- Good, because the language server can run in a web worker, enabling a browser-based playground with approximately 95% code reuse
-- Good, because `bpmn-moddle` (the standard TypeScript library for BPMN 2.0 XML) integrates naturally
+- Good, because `bpmn-moddle` (the standard JavaScript library for BPMN 2.0 XML) integrates naturally
- Good, because Langium is actively maintained by TypeFox as an Eclipse Foundation mature project
- Bad, because Langium has no built-in AST-to-text serializer, requiring a handwritten emitter for the BPMN-to-DSL reverse transformation
- Bad, because documentation has gaps for advanced topics such as custom scoping patterns
diff --git a/docs/decisions/0004-use-vscode-as-primary-ide-target.md b/docs/decisions/0004-use-vscode-as-primary-ide-target.md
index ef7911d..04d90bb 100644
--- a/docs/decisions/0004-use-vscode-as-primary-ide-target.md
+++ b/docs/decisions/0004-use-vscode-as-primary-ide-target.md
@@ -4,7 +4,7 @@ date: 2026-04-13
decision-makers: Marlon Kranz
---
-# Use VS Code as Primary IDE Target
+# Use VS Code as the primary IDE target
## Context and Problem Statement
@@ -26,11 +26,11 @@ Which IDE should be the primary target?
## Decision Outcome
-Chosen option: "VS Code (primary) with IntelliJ as stretch goal via LSP", because Langium generates a VS Code extension natively, and LSP provides a path to IntelliJ support via LSP4IJ without additional framework-specific work.
+Chosen option: "VS Code (primary) with IntelliJ as stretch goal via LSP", because Langium's project template provides a VS Code extension that hosts the language server ([ADR-0003](0003-use-langium-as-language-workbench.md)), and LSP provides a path to IntelliJ support via LSP4IJ without additional framework-specific work.
### Consequences
-- Good, because Langium generates a working VS Code extension from the grammar with no additional framework
+- Good, because the language server is built on the grammar and hosted by a VS Code extension from the Langium project template, with no additional framework
- Good, because LSP-based architecture enables IntelliJ support (via LSP4IJ) as a secondary target
- Good, because the same language server can be reused in a browser-based Monaco editor
- Neutral, because IntelliJ integration via LSP is functional but lacks deep features such as native syntax highlighting
diff --git a/docs/decisions/0005-in-editor-conversion-webview-sidebar.md b/docs/decisions/0005-in-editor-conversion-webview-sidebar.md
index 85cd107..171ee59 100644
--- a/docs/decisions/0005-in-editor-conversion-webview-sidebar.md
+++ b/docs/decisions/0005-in-editor-conversion-webview-sidebar.md
@@ -4,12 +4,12 @@ date: 2026-06-28
decision-makers: Marlon Kranz
---
-# In-Editor Conversion: Webview Sidebar and Two Layers
+# In-editor conversion: a webview sidebar and two layers
## Context and Problem Statement
-The only way to compile `.bpmnscript` to `.bpmn` or decompile `.bpmn` to `.bpmnscript` was the `bpmns` CLI.
-The CLI entry points (`buildAction`/`parseAction`) bake in `process.exit()` and `console.log`, making them unusable inside the VS Code extension host.
+Without an editor surface, the `bpmns` CLI is the only way to compile `.bpmnscript` to `.bpmn` or decompile `.bpmn` to `.bpmnscript`.
+The CLI entry points (`buildAction`/`parseAction`) bake in `process.exit()` and `console.log`, which makes them unusable inside the VS Code extension host.
Three related questions arose.
Which surface should the in-editor conversion use, a native VS Code tree view or a webview panel in a dedicated activity-bar container?
How should the conversion logic be structured so it can be tested without the VS Code host, which is unavailable under plain vitest?
diff --git a/docs/decisions/0006-target-users-without-bpmn-knowledge.md b/docs/decisions/0006-target-users-without-bpmn-knowledge.md
index 6f45ef7..7a83ef7 100644
--- a/docs/decisions/0006-target-users-without-bpmn-knowledge.md
+++ b/docs/decisions/0006-target-users-without-bpmn-knowledge.md
@@ -36,16 +36,15 @@ Decided in the supervision meeting of 2026-06-30.
## Decision Outcome
Chosen option: "Assume general programming literacy but no BPMN knowledge, and minimize required syntax".
-Concretely, two rules bind future grammar decisions:
+Two rules bind every grammar decision.
-1. No BPMN prerequisite.
- Reading or writing a `.bpmnscript` file must not require knowing BPMN.
- Keywords name what the user means (a step a person performs, a step the system performs, a decision), not the BPMN element behind it.
-2. Defaults over declarations.
- Whenever the compiler can infer or synthesize a detail, the grammar must not require the user to write it.
- When two designs express the same process, the one with less required text wins.
+The first is that reading or writing a `.bpmnscript` file must not require knowing BPMN.
+Keywords name what the user means (a step a person performs, a step the system performs, a decision), not the BPMN element behind it.
-Implicit sequence flow (ADR-0011) and synthesized structural ids (ADR-0010) already follow both rules; this decision makes them binding for what comes next.
+The second is defaults over declarations.
+Whenever the compiler can infer or synthesize a detail, the grammar must not require the user to write it.
+When two designs express the same process, the one with less required text wins.
+Implicit sequence flow (ADR-0011) and synthesized structural ids (ADR-0010) follow both rules.
The second rule stops at the compiler's output boundary, which is BPMN XML.
`bpmns build` compiles a `.bpmnscript` file to a `.bpmn` file, `bpmns parse` decompiles it back, and delegate classes are hand-written in a separate host application, as in `examples/spring-boot/`.
@@ -60,7 +59,7 @@ The generated scaffold is a long-lived support surface of its own, in dependency
- Good, because grammar discussions get a tiebreaker instead of re-arguing the audience each time.
- Good, because no lossy construct enters the language and the IR stays free of host-language code, so the round-trip guarantees hold for everything the surface admits.
- Good, because a deploy command stays a thin REST client, the mechanics the end-to-end test adapters (`tests/fixtures/adapters/`) already exercise.
-- Bad, because hiding BPMN vocabulary makes the DSL-to-XML correspondence less obvious for BPMN-literate readers; documentation has to carry that mapping, and the README glossary is a start.
+- Bad, because hiding BPMN vocabulary makes the DSL-to-XML correspondence less obvious for BPMN-literate readers; documentation has to carry that mapping, starting with the [glossary](../glossary.md).
- Bad, because every default the grammar adopts is a rule the round trip must invert, synthesized on compile and elided on decompile, growing the mapping surface that ADR-0010 normalization already covers for ids.
- Bad, because delegates are written and kept in sync by hand; the `class: "..."` string is not checked against any Java source, so a mismatch surfaces only at engine runtime.
- Bad, because the one-file authoring experience is not available: a process and the code its steps call live in separate files.
diff --git a/docs/decisions/0009-auto-layout-and-expansion-hint.md b/docs/decisions/0009-auto-layout-and-expansion-hint.md
index 46e050b..c67745d 100644
--- a/docs/decisions/0009-auto-layout-and-expansion-hint.md
+++ b/docs/decisions/0009-auto-layout-and-expansion-hint.md
@@ -38,7 +38,7 @@ It serializes DI-less BPMN XML and hands it to `bpmn-auto-layout`, which lays ou
Fed DI-less XML containing a `bpmn:subProcess`, the library does not throw, and it does not produce a degraded-but-sane result either: it renders the sub-process as a collapsed box and scatters shapes for its nested children into the root plane, at coordinates that duplicate unrelated top-level elements.
The output parses and validates, so nothing signals the problem, while a viewer opening the generated diagram shows the sub-process's children floating on top of sibling top-level elements instead of nested inside their parent.
-The library reads an existing shape's `isExpanded` flag before computing bounds, and simply had nothing to read when no shape pre-existed.
+The library reads an existing shape's `isExpanded` flag before computing bounds, and has nothing to read when no shape pre-existed.
Supplying that one boolean per sub-process is the smallest input that makes it take the branch it already has for expanded containers.
Before calling `moddle.toXML`, `irToXml` walks the built moddle tree for every `bpmn:SubProcess` element at any nesting depth.
diff --git a/docs/decisions/0010-deterministic-synthesized-ids.md b/docs/decisions/0010-deterministic-synthesized-ids.md
index b88d88d..ddc67c9 100644
--- a/docs/decisions/0010-deterministic-synthesized-ids.md
+++ b/docs/decisions/0010-deterministic-synthesized-ids.md
@@ -4,7 +4,7 @@ date: 2026-06-12
decision-makers: Marlon Kranz
---
-# Deterministic ids for synthesized elements, reserved and respelled
+# Deterministic ids for synthesized elements, reserved, and authored ids kept as written
## Context and Problem Statement
@@ -14,7 +14,7 @@ How should these ids be generated, and what does an author's own name have to st
The spelling of an author's id is the other half of the same question.
A BPMN id is an `xs:ID`, while the script's name slot is the `ID` terminal: letters, digits and `_`, a `-` between them, and no keyword.
-An id such as `Task.1`, `user`, `Review-` or `WFP-6-` (the MIWG reference models) is a legal id the script cannot spell.
+An id such as `Task.1`, `user`, `Review-` or `WFP-6-` (the MIWG reference models) is a legal id the `ID` terminal cannot spell.
The Modeler names its default start `StartEvent_1`, and 25 of 44 real exported diagrams sampled from public example repositories carry that id, so whatever the validator reserves for a start decides whether a typical Modeler diagram imports intact.
Renaming such an element is not a fix the user can apply without cost: the engine keys history (`HistoricActivityInstance.getActivityId`), migration plans (`MigrationPlanBuilder.mapActivities`) and a modification (`InstantiationBuilder.startBeforeActivity`) on the activity id.
@@ -25,22 +25,24 @@ Renaming such an element is not a fix the user can apply without cost: the engin
- Sequential counters depend on traversal order, making ids sensitive to unrelated source changes.
- Ids derived from structural position are self-documenting and survive refactoring of unrelated parts of the process.
- The import contract ([ADR-0012](0012-honest-bpmn-import.md#decision-outcome)): a document that deploys imports, unless it marks more than one process executable, holds an event without an id that the engine deploys but cannot run, or uses a construct this surface cannot spell, and every change to what runs is reported.
-- An activity id is the key the engine's history and migration match on, so a changed id is a changed process, and the report has to say so.
+- An activity id is the key the engine's history and migration match on, so a changed id is a changed process, and the script has to be able to write every id it has a name slot for.
- One fact, one home: the shape of a name is the `ID` terminal, and the transform spells it once for both directions.
## Considered Options
-- Structural coordinate: an id derived from the element's position in the process body, with the exact minted ids reserved against author names and an unspellable id respelled on print, matching exactly what the compiler mints so every legal document prints as source that recompiles unchanged
+- Structural coordinate: an id derived from the element's position in the process body, with the exact minted ids reserved against author names, matching exactly what the compiler mints so every legal document prints as source that recompiles unchanged
- UUIDs, random and non-deterministic
- A sequential counter, deterministic but traversal-order-sensitive
- Reserving a `StartEvent_` and `EndEvent_` prefix rather than the exact minted ids, and renaming a Modeler default start on import: one rule for both directions without a per-container lookup, but renaming the one element every Modeler diagram has changes most imports' activity id, and without the rename that start is either dropped from the script with its label and initiator or printed and refused on read-back
- Refusing every id the script cannot spell: nothing then prints under a name the model does not carry, but the MIWG reference models and any diagram with a dotted or hyphen-terminated id would not import at all, although the engine deploys them
+- Respelling an id the `ID` terminal cannot spell on print, with a warning: every document imports, but the rebuilt document carries the respelled id, so the engine's history and migration APIs no longer know the process, and the only remedy is a rename in the model
+- A second name form in backticks that spells any id the engine deploys: every id with a name slot survives import and rebuild, at the cost of a second spelling for a name and one more terminal in the grammar
## Decision Outcome
-Chosen option: the structural coordinate with exactly reserved names.
+Chosen option: the structural coordinate with exactly reserved names, and a name form in backticks for an authored id the `ID` terminal cannot spell.
Deriving each id from the element's position in the source makes recompilation reproducible, keeps golden tests stable, and lets a reader trace a synthesized id back to the statement that produced it.
-Reserving the exact forms the compiler mints, and respelling an id the script cannot spell, keeps every document importable while reporting the one change it makes.
+Reserving the exact forms the compiler mints, and writing every other id as it stands, keeps every document importable without changing an id the script has a slot for.
The frozen id templates (from `packages/transform/src/synthesize-ids.ts`):
@@ -71,7 +73,7 @@ If a base id is already in the taken set, the resolution appends `_2`, `_3`, and
Gateway ids skip the `taken`/`resolveCollision` guard, because the position-path scheme never generates the same id twice.
What collides with them is an author-chosen statement name matching a synthesized-id pattern.
The `checkReservedNames` validator in `packages/language/src/bpmn-script-validator.ts` rejects such a name at validation time.
-It reserves by prefix `Gateway_*_(split|join|fork|loop|race)`, `Throw_*`, `EventSubProcess_*`, `Boundary_*`, `Catch_*`, and the two-segment `Flow_*_*` form (`/^Flow_.+_.+$/`).
+It reserves by prefix `Gateway_*_(split|join|fork|loop|race)`, `Throw_*`, `EventSubProcess_*`, `Boundary_*`, `Catch_*`, the two-segment `Flow_*_*` form (`/^Flow_.+_.+$/`), and the `*_di` suffix diagram-interchange ids carry.
Single-segment names such as `Flow_Control` stay legal, because synthesized flow ids occupy only `SequenceFlow.id` and never node names, so they cannot collide.
For a start and an end it reserves, for each statement, the exact `StartEvent_` and `EndEvent_` of the container `c` whose body holds it: the process, or the nearest `subprocess` or `attempt` block.
The message says the compiler generates that id for the container's implicit start or end.
@@ -86,14 +88,20 @@ A statement named `default` in an earlier branch of such a split spells that str
The printer recognizes a minted start or end by the same exact forms, plus `EndEvent_` for a boundary in the same container and the `Throw_` prefix an unnamed throw lowers to.
Only those are left out, since the compiler re-derives them; a start or end under any other id prints with its label, its documentation and its initiator.
-The printer builds one map per print, from the process id and every element id that prints, to the name each is written under.
-An id the `ID` terminal accepts maps to itself.
-Any other maps to the id with every non-word character replaced by `_`, a leading `_` where the result would open on a digit or read as a keyword, resolved against every id in the document and every name minted before it.
-Every site that writes an id reads the map: the process head, every statement head, a `goto`, a boundary's host, and a named throw or catch.
-A gateway of any kind, a boundary event, an event sub-process, the catch event of a race branch and a sequence flow have no id slot in the script, so the map leaves them out.
+Every name slot takes the plain `ID` or the `QUOTED_NAME` terminal: any text on one line between backticks, where a backslash takes the next character literally, as in `` user `Task.1` `` or `` goto `end` ``.
+Both carry the bare text, so `` `Review` `` and `Review` are one name to the linker, the duplicate check and every reference.
+The printer writes an id plainly where the `ID` terminal lexes it as no keyword, and in backticks otherwise (`printName` in `packages/language/src/vocabulary.ts`).
+Every site that writes an id goes through it: the process head, every statement head, a `goto`, a boundary's host, and a named throw or catch.
+A gateway of any kind, a boundary event, an event sub-process, the catch event of a race branch and a sequence flow have no id slot in the script.
Their authored ids do not survive a rebuild: the compiler synthesizes each one from the templates above, and no warning reports it.
An element with a name slot keeps its id: a task, a sub-process, a start, an end, a single `await`, and a named `throw` or `emit`.
-Each rename draws one `renamedId` warning naming the printed name and saying that the rebuilt document carries it as the activity id.
+
+A name in backticks still becomes an id, so the validator holds a process or statement name to ASCII letters, digits, `_`, `-` and `.`, starting with a letter or `_` (`ENGINE_ID_TEXT`).
+Operaton validates every file against `BPMN20.xsd`, which types an id as `xs:ID` and refuses a space or a leading digit, and moddle-xml drops an element whose id holds any letter beyond ASCII.
+The import refuses a document with an id outside the same set, such as one with a `:`, which moddle-xml reads as a qualified name and the schema refuses.
+The reserved forms above stay reserved in backticks too, because what collides is the id the compiler mints, not its spelling.
+A code declaration's name is the root's `name` attribute rather than an id, so in backticks it takes any text on one line, and import keeps the root's `name` as written.
+A code is referenced inside a trigger's parens, which the grammar parses as an expression, so a name in backticks is read there and refused anywhere else in an expression, since a variable has no backtick form.
An element the document gives no id gets one on import, before anything keys it.
A sequence flow gets `Flow__`, and any other element `_`, from the local name of its BPMN type and the id of the process or sub-process holding it, such as `UserTask_invoice`; both resolve against every id in the document the way the compiler's ids do.
@@ -112,11 +120,11 @@ The engine sets the variable under that exact name (`FormFieldHandler.handleSubm
- Good, because re-compiling the same source always produces the same BPMN ids, and golden files stay stable across unrelated source changes.
- Good, because the id scheme is self-documenting: reading a gateway id reveals its position in the source.
- Good, because `synthesize-ids.ts` is a pure, dependency-free module with its own test suite.
-- Good, because a Modeler default diagram imports, prints and rebuilds with its start's id, label and initiator intact, and a MIWG reference model prints as source that parses and validates, with one report per id it could not keep.
+- Good, because a Modeler default diagram imports, prints and rebuilds with its start's id, label and initiator intact, and a MIWG reference model prints as source that parses, validates and rebuilds with every activity id it carries.
- Neutral, because the structural coordinate is longer than a UUID, making gateway ids verbose in deep nesting, mitigated by the fact that deeply nested processes are rare in the current scope.
- Bad, because renaming a process id or reordering top-level statements changes all synthesized ids in that process, which breaks deployed BPMN definitions.
That is a concern for production use and acceptable for a DSL-authoring workflow where recompile is expected to replace the definition.
-- Bad, because a respelled id is a changed activity id in the rebuilt document, so a process rebuilt from such a script is not the process the history and migration APIs know; the warning says so, and the remedy is a rename in the model.
+- Neutral, because a name has two spellings, and the printer uses backticks only where the plain one cannot spell the id, so a script written by hand rarely shows them.
- Bad, because an imported gateway, boundary event, event sub-process or race-branch catch comes back under a synthesized id without a warning, and the engine records these in history under their activity id as it does a task.
A migration plan written against the original document has to map them anew.
- Bad, because a statement written under another container's minted id, such as `user EndEvent_S` beside `subprocess S`, is legal and makes the compiler mint `EndEvent_S_2` for `S`, which the printer then writes as an ordinary `end EndEvent_S_2`; the round trip stays stable from the second print on, and nothing runs differently.
@@ -125,7 +133,8 @@ The engine sets the variable under that exact name (`FormFieldHandler.handleSubm
`packages/transform/test/synthesize-ids.test.ts` verifies every template, the collision-resolution rule, and the exact predicates for a minted start and end.
The reserved-name table in `packages/language/test/validating.test.ts` pins the exact rule per container and the freed `StartEvent_1`.
-The respelling table in `packages/transform/test/ir-to-dsl.test.ts` prints every id site under a minted name, asserts the whole warning list, and re-parses and validates the source; the Modeler-default row asserts the printed start, end and initiator with no warning.
+The backtick table in `packages/transform/test/ir-to-dsl.test.ts` prints every id site in backticks with no warning, re-parses and validates the source, and compiles it back to the same ids; the Modeler-default row asserts the printed start, end and initiator with no warning.
+`tests/backtick-names.round-trip.test.ts` imports a document per id the plain form cannot spell, asserts the exact printed script, and compiles it to a document with the same ids and no model difference.
The refusal matrix in `packages/transform/test/xml-to-ir.test.ts` pins the two import refusals.
The two id-less tables in the same file pin the minted ids and the id-less events that refuse.
The round-trip normalizer (`tests/helpers/normalize-ir.ts`) uses the id patterns to re-key synthesized ids before comparing IR snapshots, and the golden pair suites pass unchanged.
@@ -135,4 +144,4 @@ The round-trip normalizer (`tests/helpers/normalize-ir.ts`) uses the id patterns
The id templates are frozen, because they are consumed by `astToIr`, `irToDsl`, and the round-trip normalizer.
Any change requires updating all three consumers and regenerating the `invoice-approval-generated.bpmn` golden file.
The frozen contract is documented in the header of `packages/transform/src/synthesize-ids.ts`, which also holds the exact predicates and the minting scheme.
-The name map is built by `printedNames` in `packages/transform/src/ir-to-dsl.ts`; the per-container check is `checkReservedNames` in `packages/language/src/bpmn-script-validator.ts`; the two import refusals go through `refuseUnspellableVariable` in `packages/transform/src/xml-to-ir.ts`.
+The printed spelling is `printName` in `packages/language/src/vocabulary.ts`; the per-container check is `checkReservedNames` and the id check `checkEngineIds` in `packages/language/src/bpmn-script-validator.ts`; the variable refusals go through `refuseUnspellableVariable` in `packages/transform/src/xml-to-ir.ts`.
diff --git a/docs/decisions/0011-structured-grammar-one-bracket-shape.md b/docs/decisions/0011-structured-grammar-one-bracket-shape.md
index 4e992c0..0ff7974 100644
--- a/docs/decisions/0011-structured-grammar-one-bracket-shape.md
+++ b/docs/decisions/0011-structured-grammar-one-bracket-shape.md
@@ -55,12 +55,9 @@ The shape is `verb Id(attributes) { children }`.
An element with no members has no brace, so `user Review(label: "Review the order", assignee: "demo")` is a complete statement, and an element with no settings has no parens.
It adds no reserved words, and the `:` inside the parens is the separator the form block and the `var` declaration already use.
-### What the shape alone does not decide
-
-A handler keeps the colon after its host, as in `on Pack: error(OUT_OF_STOCK, code: c)`.
-Dropping it makes a hostless handler carrying a code and a hosted handler carrying none both read as `on` followed by two identifiers.
-No lookahead separates those, because the trigger words are soft identifiers and the host is a cross-reference the parser cannot resolve while it is parsing.
-The same colon settles the same question for `throw` and `emit`.
+The shape alone leaves four things open.
+A handler keeps the colon after its host, as in `on Pack: error(OUT_OF_STOCK, code: c)`, for the reason [ADR-0027](0027-boundary-events-attached-to-an-activity.md) gives.
+`throw`, `emit` and `await` settle the same question without a colon by writing their optional name after the trigger word, as in `throw error PaymentFailed(PAYMENT_DECLINED)`.
A trigger keeps its own slot, so an event-bearing element reads `verb Id trigger(payload, settings) { children }`.
The payload is positional, since `TriggerPayloadRule` gives every trigger at most one code, and a key would spell that code's role twice.
diff --git a/docs/decisions/0012-honest-bpmn-import.md b/docs/decisions/0012-honest-bpmn-import.md
index fe374bc..92bce91 100644
--- a/docs/decisions/0012-honest-bpmn-import.md
+++ b/docs/decisions/0012-honest-bpmn-import.md
@@ -8,9 +8,9 @@ decision-makers: Marlon Kranz
## Context and Problem Statement
-`xmlToIr`'s docstring stated that silent semantic loss is impossible, while the transform dropped several kinds of content without any diagnostic: event definitions on start and end events, loop characteristics on tasks, whole collaborations, Operaton and camunda extension content, and lanes.
+An importer that promises no silent semantic loss has to say what happens to every piece of content the IR cannot carry: event definitions on start and end events, loop characteristics on tasks, whole collaborations, Operaton and camunda extension content, and lanes among them.
Some of those drops change what the imported process executes; others do not.
-The import contract has to make good on its own claim: what should happen when `xmlToIr` meets content the IR cannot carry, and should every such case be treated the same way?
+What should happen when `xmlToIr` meets content the IR cannot carry, and should every such case be treated the same way?
A surface that answers from its own reading of the IR disagrees with `BpmnParse` in both directions, refusing files the engine deploys while carrying files it refuses, and it says nothing about what the engine does with what it drops.
Camunda Modeler's default export is the case that costs most: it writes a `bpmn:collaboration` with one participant for any diagram with a pool or a lane, an `isExecutable="false"` process for every empty pool, and `xmlns:camunda` on every file, which is also the shape of the Operaton invoice example and four MIWG reference files.
@@ -30,10 +30,10 @@ Document shapes the engine rejects before `BpmnParse` sees an element pass throu
- Two tiers drawn where `BpmnParse` draws them: refuse what the engine fails the deployment on, warn on what it deploys and this surface cannot spell.
- Refuse everything the IR cannot express, with no warning tier: nothing the engine runs is ever dropped and a listener on a gateway could not slip through, but it refuses every file a real modeler exports over content that costs the reader a warning rather than a run.
-- Drop what the IR cannot carry in silence and correct the docstring to describe that.
+- Drop what the IR cannot carry in silence and document that the importer does so.
- Draw the tiers from the surface's own reading of the IR and correct the wording of the drops alone.
- Refuse every setting the engine reads that this surface cannot spell.
-- Refuse every collaboration and every multi-process document, on the reading that a pool means several linked processes: nothing is dropped, but the refusal blocks most real input on a shape the engine ignores, and its message called a lone pool "multiple linked processes".
+- Refuse every collaboration and every multi-process document, on the reading that a pool means several linked processes: nothing is dropped, but the refusal blocks most real input on a shape the engine ignores, and its message would call a lone pool "multiple linked processes".
- Write the pool back on export rather than warn that the round trip loses it: the frame would survive, but it needs a `bpmn:collaboration`, a participant shape whose bounds enclose every laid-out element, and a plane over the collaboration, none of which `bpmn-auto-layout` produces, for a frame the engine never reads.
- Read the camunda namespace through a second moddle package, or by rewriting the prefix in the document text: a second package would key every consumption table twice, and a prefix rewrite could hit a prefix spelled inside attribute text, where the URI cannot appear.
- Carry documentation as a list of `{ text, textFormat }` members per node, or rework the printer to give a setting a multi-line entry: nothing in the corpus writes two children on one element, so neither buys anything the single escaped string does not.
@@ -45,7 +45,7 @@ Document shapes the engine rejects before `BpmnParse` sees an element pass throu
Chosen option: two tiers, drawn where `BpmnParse` draws them, because it is the only option consistent with the no-silent-semantic-loss claim that accepts what the engine deploys, within the scope bounds below (one executable process per file, no event without an id that the engine deploys but cannot run, and no construct this surface cannot spell), and says what the engine does with what it drops.
The rule has three clauses.
-A shape `BpmnParse` fails the deployment on refuses, and the message names the method and quotes its sentence, since there is nothing that runs to write back.
+A shape `BpmnParse` fails the deployment on refuses, and the message names the method, since there is nothing that runs to write back.
A shape the engine deploys and this surface can spell is carried, with a warning where the spelling changes.
A shape the engine deploys and this surface cannot spell either drops with a warning that names the method that reads it and says the document written back runs without it, or is refused with its reason.
`packages/transform/README.md` lists the refused ones, among them a `bpmn:complexGateway`, a compensation boundary event, two input parameters sharing a name, a script body no fence can enclose, and a thrown message's result variable beside an `expression` binding, where the engine stores a value the throw has no slot for.
@@ -66,6 +66,9 @@ Three document-level shapes follow from the same rule rather than from any one e
A file with two or more processes marked executable is refused, although `parseProcessDefinitions` deploys each of them as a definition of its own: the IR and a script hold one process, so one executable process per file is a scope bound of this tool, not an engine rule.
A collaboration is diagram data to the engine, since `parseCollaboration` records a participant's `processRef` only so that `parseBPMNShape` can attach the pool's bounds and no method in `BpmnParse` reads a `bpmn:messageFlow`, so a pool warns rather than refuses.
The camunda namespace is read as the operaton one by replacing the URI in the document text before `moddle.fromXML`, with one warning per document: `BpmnParse.OPERATON_BPMN_EXTENSIONS_NS` falls back to the camunda URI only when the operaton lookup finds nothing, and moddle-xml binds a prefix to a package by URI rather than by spelling, so after the swap every `camunda:` element arrives typed `operaton:*` and every `camunda:` attribute reads through the one `operaton:` reader.
+That fallback runs per attribute name on one element and per child tag name under one parent (`Element.attributeNS`, `elementNS`, and `elementsNS`), so a file declaring both URIs would merge two spellings the engine keeps apart.
+Before the swap, the camunda spellings the engine never reaches are cut from the text, and one `extensionAttribute` warning per element names them.
+Children `BpmnParse` fetches by tag alone, such as list items, map entries, and an external task's `errorEventDefinition`, run under both spellings and import under both.
BPMN's own resource roles on a user task import onto the Operaton assignment attributes, with one warning per role naming the rewrite, since `BpmnParse.parseTaskDefinition` reads both into the same assignee and candidate lists that `operaton:assignee`, `operaton:candidateUsers`, and `operaton:candidateGroups` fill.
The exported document carries the Operaton attributes alone, and the engine builds the same identity links from them.
@@ -74,18 +77,26 @@ A single plaintext `bpmn:documentation` child imports onto one optional `documen
The body is carried verbatim, so a modeler's pretty-printed whitespace inside the element comes back as it was written rather than trimmed.
Tying documentation to the name means the positions that report it instead are already the positions a label is reported at: an element with no slot for a name has no slot for documentation either, so there is one rule rather than two.
+A documentation child inside a value the engine reads is carried as well, since BPMN gives every expression the base element's `documentation`.
+The values are a condition on a sequence flow or a conditional event, a timer's time, a repetition's count and completion condition, and the `bpmn:inputDataItem` naming the variable each run sees.
+`documentation` always documents the element, and a value always takes a key named for the word that introduces it: `conditionDocumentation`, `timerDocumentation`, `countDocumentation` or `eachDocumentation`.
+So `if (amount > 1000, conditionDocumentation: "...")` documents the condition and leaves the parentheses after it to the gateway, and `user R for 3 until (done, conditionDocumentation: "...")` documents the completion condition.
+A `documentation` inside a condition's own parentheses is refused, since it would document a value under the element's key.
+The writer puts a documented expression's text flush against its documentation child, because `BpmnParse` reads a loop count and a completion condition untrimmed and the formatter's indentation would otherwise become part of them.
+A documented element variable is written as a named `bpmn:inputDataItem` instead of `operaton:elementVariable`, which `parseMultiInstanceLoopCharacteristics` reads into the same field, and a `bpmn:inputDataItem` without a name has no variable to hold the text, so its documentation is reported.
+
The contract covers two hops.
`irToDsl` reports in the same shape, returning `{ source, warnings }` for the reason `xmlToIr` returns `{ ir, warnings }`: a channel a caller can skip is a silent drop.
-Some of what its warnings name merely drops, such as a gateway label no statement form can hold; some changes what a recompiled document runs, such as a fallback re-derived on an imported fork whose branches all carry conditions and that named none; and some is printed as the model spells it and draws an error when the source is read back, such as an `else` beside a branch that runs whatever the conditions do.
+Some of what its warnings name merely drops, such as a gateway label no statement form can hold; some changes what a recompiled document runs, such as an inclusive split degraded to jumps, whose recompiled form takes one route where the model takes every route whose condition holds; and some is printed as the model spells it and draws an error when the source is read back, such as an `else` beside a branch that runs whatever the conditions do.
Every one of them is warned rather than refused, because a refusal has no meaning on this hop: the restructurer is total and always produces source.
### Consequences
-- Good, because a document the engine deploys imports, provided it marks at most one process executable, holds no event without an id that the engine cannot run, and uses no construct this surface cannot spell, among them the Modeler's default collaboration file, the Operaton invoice example, and the MIWG files with one executable process, and one the engine refuses is refused with the engine's own sentence rather than imported into a script that cannot deploy.
+- Good, because a document the engine deploys imports, provided it marks at most one process executable, holds no event without an id that the engine cannot run, and uses no construct this surface cannot spell, among them the Modeler's default collaboration file, the Operaton invoice example, and the MIWG files with one executable process, and one the engine refuses is refused with the name of the engine method that refuses it rather than imported into a script that cannot deploy.
- Good, because every caller, the CLI, the VS Code extension, and the round-trip suite, surfaces both the refusal and the warning channel instead of only one or neither, and the shared `UnsupportedConstructError` base keeps classification to one `instanceof` check as new refusal categories are added.
- Good, because every warning on a setting the engine reads says which method reads it, so the reader knows whether the drop changes a run.
- Bad, because the engine's sentences are quoted in the importer and drift with the engine's wording.
-- Bad, because a shape the engine deploys and then fails at run time, such as an empty listener `class` on a task, is carried into a script that draws an error at the step, which the reader has to repair by hand.
+- Bad, because a shape the engine deploys and then fails at run time, such as an empty task listener `class`, is carried into a script that draws an error at the step, which the reader has to repair by hand.
- Bad, because some warned items do bear on what runs, against the boundary this decision draws, among them a dropped `operaton:field`, which leaves the bound class without a value it was injected with, and `isExecutable="false"`, which imports as an executable process.
Refusing either would reject files that otherwise import cleanly, and carrying `isExecutable` through would mean an IR field, a serializer path, and a DSL surface for a flag this tool has no use for.
- Bad, because the round trip rewrites a document in places: the pool is gone, so a pooled diagram opens as a plain process, and a `bpmn:potentialOwner` comes back as `operaton:candidateGroups`.
@@ -94,12 +105,13 @@ Every one of them is warned rather than refused, because a refusal has no meanin
### Confirmation
-The refusal and warning tables in `packages/transform/test/xml-to-ir.test.ts` pin every documented row with the whole warning list or the refusal class and detail, including the document level, the `camunda: prefix alias` describe, the resource-role merge, and the quantity warning.
+The refusal and warning tables in `packages/transform/test/xml-to-ir.test.ts` pin every documented row with the whole warning list or the refusal class and detail, including the document level, the `camunda:` file and the setting spelled under both prefixes, the resource-role merge, and the quantity warning.
`tests/review-loop.round-trip.test.ts` and the invoice fixture in `tests/` pin the Modeler-shaped documents end to end, and `tests/e2e/forms-and-external-tasks.test.ts` deploys the re-export of a task assigned in BPMN's own words to a real engine and reads the identity links back.
The frozen `documentation` golden pair and a parameterized sweep per hop name every position that carries documentation and every position that reports it instead, so a position wired to neither branch fails the sweep rather than passing in silence.
+`tests/value-documentation.round-trip.test.ts` takes every value position through one table, from script to XML and back and from that XML to a rebuild with no model difference.
## More Information
-The refuse and warn boundary and the `ImportWarning` shape (`elementId`, `category`, `message`) live in `packages/transform/src/errors.ts` and `packages/transform/src/xml-to-ir.ts`, where the checks are `refuseDocumentShapes`, `refuseDroppedIds`, `refuseImports`, `selectProcess`, `warnCollaborationDrops`, `checkExclusiveGateways`, `checkStartEventCount`, `checkHandlerFlows`, `attachDefaultFlows`, `refuseIoMapping`, `onlyExtensionElement`, `resolveListenerBinding`, `readThrownMessageBinding`, and the `ENGINE_READS_ELSEWHERE` table behind `warnUnimportedSetting`; the namespace swap sits at the top of `xmlToIr`.
+The refuse and warn boundary and the `ImportWarning` shape (`elementId`, `category`, `message`) live in `packages/transform/src/errors.ts` and `packages/transform/src/xml-to-ir.ts`, where the checks are `refuseDocumentShapes`, `refuseDroppedIds`, `refuseImports`, `selectProcess`, `warnCollaborationDrops`, `checkExclusiveGateways`, `checkStartEventCount`, `checkHandlerFlows`, `attachDefaultFlows`, `refuseIoMapping`, `onlyExtensionElement`, `resolveListenerBinding`, `readThrownMessageBinding`, and the `ENGINE_READS_ELSEWHERE` table behind `warnUnimportedSetting`; the namespace swap sits at the top of `importDocument`, which `xmlToIr` calls.
`PrintWarningCategory` and the warnings built beside it in `packages/transform/src/ir-to-dsl.ts` settle which reports the print hop makes and what each one costs.
The consumer-facing summary is the import contract section of `packages/transform/README.md`.
diff --git a/docs/decisions/0013-validator-mirrors-parse-time-rules.md b/docs/decisions/0013-validator-mirrors-parse-time-rules.md
index cb645d7..4deb84c 100644
--- a/docs/decisions/0013-validator-mirrors-parse-time-rules.md
+++ b/docs/decisions/0013-validator-mirrors-parse-time-rules.md
@@ -8,16 +8,16 @@ decision-makers: Marlon Kranz
## Context and Problem Statement
-`BpmnParse` refuses a set of documents at deployment that this surface compiled without a word.
+`BpmnParse` refuses a set of documents at deployment that a validator blind to the engine compiles without a word.
`addEventSubscriptionDeclaration` keeps one message or signal subscription per name on one scope, and one conditional start per condition text on the process.
A handler written inside a block subscribes on that block, since the event sub-process it lowers to takes the block as its event scope (`parseEventDefinitionForSubprocess`), and a handler attached to the block subscribes on the block too (`parseBoundaryEvents`), so the two collide on one name.
Every branch of an `await` block subscribes on the gateway (`parseIntermediateCatchEvent`), so two branches on one name collide as well.
`addEscalationEventDefinition` refuses an escalation catch without a code beside one with a code when both are boundary events on one host or both event sub-processes in one scope.
`selectInitial` refuses a second plain or timer start on a process.
-The validator keyed a handler by its host name and grouped handlers by syntactic container, so none of these collisions drew a diagnostic, and the deployment failed with an engine message naming a generated id.
+A validator that keys a handler by its host name and groups handlers by syntactic container draws no diagnostic for any of these collisions, and the deployment fails with an engine message naming a generated id.
Three more facts sit beside those, silent rather than refused.
-`parseScopeStartEvent` reads neither `operaton:initiator` nor a start form off a start that is not the process's own, so both compiled onto a nested start and did nothing.
+`parseScopeStartEvent` reads neither `operaton:initiator` nor a start form off a start that is not the process's own, so both compile onto a nested start and do nothing.
`DefaultFailedJobParseListener.parseActivity` stores a retry cycle only for an activity with an async flag, and `parseAsynchronousContinuation` folds `exclusive` into the async flags it sets.
`createActivityOnScope` stores a job priority that only a job declaration reads.
Each of the three keys therefore configures nothing without the job its async flag creates.
@@ -60,10 +60,10 @@ A timer carrier is exempt for all three, since the timer job reads them off the
### Consequences
-- Good, because a script that compiles now deploys where these rules are concerned, and the message names the scope and the engine method.
+- Good, because a script that compiles also deploys where these rules are concerned, and the message names the scope and the engine method.
- Good, because a setting that configures nothing is reported at the key that carries it.
- Bad, because the validator restates engine rules that can move under a new engine version; each rule cites the method it mirrors so the drift can be checked.
-- Neutral, because a script with a nested start form, an unpaired job setting, or a `resultVariable` beside `topic` draws a diagnostic where it drew none.
+- Neutral, because a script with a nested start form, an unpaired job setting, or a `resultVariable` beside `topic` draws a diagnostic although it deploys.
### Confirmation
diff --git a/docs/decisions/0014-restructure-the-ir-into-a-dsl-with-dominator-analysis.md b/docs/decisions/0014-restructure-the-ir-into-a-dsl-with-dominator-analysis.md
index 4e403f4..a44fec6 100644
--- a/docs/decisions/0014-restructure-the-ir-into-a-dsl-with-dominator-analysis.md
+++ b/docs/decisions/0014-restructure-the-ir-into-a-dsl-with-dominator-analysis.md
@@ -33,14 +33,14 @@ How should `irToDsl` decide which subgraphs can be phrased as `if`, `while`, `pa
- Ad-hoc recursive pattern matching without formal control-flow analysis: there is no criterion to check a match against, so an unstructured graph has no defined outcome and the decompiler is free to loop or to throw.
- An `if` chain for a step with more than one route out, and jumps carrying no conditions where a split degrades: the print of a common modeler shape, a task with two plain flows, then runs one route where the model runs both, and a degraded split's conditions are discarded with no marker for the reader to find.
- Refusing a step with more than one outgoing flow on import: the printer never sees the shape, but the engine deploys and runs it, and the import contract refuses only what the engine refuses or what changes a stored value.
-- Keeping a split whose every route is conditioned as jumps wherever it sits: the print reports the drop and no rule is added, but a condition on every route with no default named is the common modeler shape, and the process the thesis demonstrates on came back running differently.
+- Keeping a split whose every route is conditioned as jumps wherever it sits: the print reports the drop and no rule is added, but a condition on every route with no default named is the common modeler shape, and the Operaton invoice example would come back running differently.
- Deferring the chain that holds an elided synthesized end to the last position in its block: it conflicts with the elided-start-first rule whenever one chain holds both, only one chain can be last where there are several elided ends, and printing the end in place covers every shape it would.
## Decision Outcome
Chosen option: dominator and post-dominator analysis with a fixed pattern catalog and a `goto` fallback, because dominator analysis gives a mechanically checkable criterion for each structured construct, and the edges the catalog cannot fold degrade to `goto` instead of to a failure.
-The analysis is `analyzeCfg(process): CfgAnalysis`, a pure function over the IR with `immediateDominator`, `immediatePostDominator`, `dominates`, `postDominates`, `backEdges`, `outgoing` and `incoming` queries.
+The analysis is `analyzeCfg(container): CfgAnalysis`, a pure function over one process or sub-process with `immediateDominator`, `immediatePostDominator`, `dominates`, `postDominates`, `backEdges`, `outgoing` and `incoming` queries.
`VIRTUAL_ENTRY` and `VIRTUAL_EXIT` give the dominator algorithm a unique single entry and exit.
The pattern catalog:
@@ -69,12 +69,10 @@ The guard clause answers when exactly one route is unconditioned, that route bei
Operaton takes the first route in document order that carries no condition or one that holds, so the chain keeps that order: a route without a condition listed before a conditioned one, the guard clause's continuation included, heads its branch as `true` in its place, and the routes after it stay in the chain although neither the engine nor the rebuilt split ever takes them.
The enclosing continuation is the stop node the enclosing construct handed down, and answers only while that node is defined, no route is unconditioned, and at least one route's target is dominated by the split and post-dominated by the stop node; the chain then walks that route inline, prints the routes that leave the region as jumps, and stops at the stop node where the enclosing construct carries on.
The same rule serves a split inside a `while` body, a `do` body and a branch, including a split inside a guarded branch.
-Outside any enclosing construct, a split whose every route is conditioned and that has no default continues at a route whose target has no other incoming flow, which leaves that target unprinted and outside any loop the split is not in: its last route in document order when that one qualifies, else its first that does.
-The recompiled split gains a fallback the model never named, which the print reports, and that fallback runs into the statement the print put after the `if`, so a second print reads the same.
-The last route prints as the chain's fall-through rather than as an empty branch, so the print builds without the validator's empty-branch warning.
-Its condition gives way to the fallback, and since Operaton tries the routes in document order and so tries that route last anyway, only the no-match case changes, which the print reports.
-Any other route keeps its condition over an empty branch, since dropping it would make the route the engine tries first the one the rebuilt split tries last.
-With no such route the jumps stay, closing with no `else`.
+Outside any enclosing construct, a split whose every route is conditioned and that has no default continues at a route whose target has no other incoming flow or is already printed: its last route in document order when that one qualifies, else its first that does.
+That route keeps its condition over an empty branch, the walk carries on at its target after the `if`, and a second print reads the same.
+Such a split stops the run when no condition holds, so its chain closes with `else fail` ([ADR-0031](0031-inclusive-and-event-based-gateways.md)) and the rebuilt split stops where the model stops.
+With no such route the jumps stay, under the same `else fail`.
A loop gateway's own exit condition prints as the fall-through after the `} while (...)` line and is reported as dropped.
Every route of a folded exclusive split gets a form: a condition heads its branch, and a route carrying none heads a branch as `true`, takes the chain's `else`, or runs straight into the join as the chain's fall-through, since heading that last route instead would put a `true` over an empty branch and leave the rest of the chain unreachable.
@@ -105,7 +103,7 @@ The compiler mints such an end in `lowerContainerBody` and `lowerBoundaryHandler
`isElidedOnPrint` stays the model-level predicate and keeps answering "the printer may drop this end", which `warnRefusedStatements`, `forwardToRealTarget` and the importer's `warnElidedNamedDrop` read.
Whether the printer does drop the end is a fact about print order, known only once every chain of the block is on the page, so that half of the decision sits in the emitter: `emitNode` records the end with the position it would have printed at, and `Emitter.emit` then leaves out an end nothing followed and splices any other back at its position, with one report per printed end, in page order.
The printed source draws exactly one validator error, on the printed `end` line, and renaming the id in the model makes the source clean and round-trips the document structurally unchanged.
-The import warning on a labelled plain end describes both outcomes, since the importer cannot know which position the printer will give an end: where the script can do without the end it is left out and its label with it, and anywhere else it prints under a name the script refuses.
+The import warning on a plain end carrying documentation describes both outcomes, since the importer cannot know which position the printer will give an end: where the script can do without the end it is left out and its documentation with it, and anywhere else it prints under a name the script refuses.
Either way the fix it names is a rename in the diagram.
### Consequences
@@ -114,15 +112,14 @@ Either way the fix it names is a rename in the diagram.
- Good, because AND fork and join pairs are recovered as `parallel` blocks without special-casing the decompiler.
- Good, because a step with two plain routes or with a weighed route beside a plain one round-trips to the routing the engine runs, with no report.
- Good, because the conditions of a degraded split survive on its jumps, and the marker line puts the reader at the split rather than leaving the jumps to explain themselves.
-- Good, because the fork printer, the invented-fallback report and the fallback-condition report each have one home, and a gateway and a step share it.
+- Good, because the fork printer, the `else fail` test and the fallback-condition report each have one home, and a gateway and a step share it.
- Good, because the CFG analysis is a pure, stateless utility with its own test suite, auditable independently of the emitter, and the same dominator queries answer the own merge, the clean join and the enclosing continuation, while `convergence` reads forward reachability and the guard clause only which routes carry a condition.
- Good, because a split whose every route is conditioned inside a loop body prints its staying routes inline, so the Operaton invoice example prints its review call inside the loop and the rebuilt process keeps the loop.
A cascade of such splits inside one body prints as nested chains, each continuing at the same stop node, and the rule adds no state to the walk.
-- Good, because the restructurer reports what it drops instead of leaving the caller to find it, including where the drop changes what a recompiled document runs.
- A fallback re-derived on an imported OR fork that named none is one such report: `InclusiveGatewayActivityBehavior` throws a stuck execution when every branch of such a fork carries a condition and none of them holds, while the printed block falls through, so a document recompiled from that script runs on where the model would have stopped.
+- Good, because the restructurer reports what it drops instead of leaving the caller to find it, including where the drop changes what a recompiled document runs, such as a degraded split whose kind is written nowhere.
- Good, because a synthesized plain end that is not its block's tail is refused loudly instead of rewiring its chain into whatever the printer appended next: the reader finds a reserved id on the page, a print warning, and a validator error naming the element to rename.
- Neutral, because a route running straight into an enclosing construct's stop node prints as an empty branch, which the validator warns about; the condition on it survives, where a jump would have lost the branch.
-- Neutral, because a step whose routes reconverge at a merge of another kind, or at a step, degrades to jumps under the marker: the block form synchronizes at a merge of its own kind, which the model does not have there.
+- Neutral, because a step whose routes reconverge at a merge of another kind degrades to jumps under the marker: the block form synchronizes at a merge of its own kind, which the model does not have there.
- Neutral, because a jump into an elided end is still dropped and marked.
`forwardToRealTarget` reads the model-level answer, and at the top level the jump is printed before the end's position is known; for a plain end in the same container the re-derived tail end is the same terminal, so the process runs the same and the marker is the only cost.
- Neutral, because RPST would recover more structured patterns, for example nested switch-like gotos, but is left for later, once the scope justifies the added machinery.
@@ -130,7 +127,7 @@ Either way the fix it names is a rename in the diagram.
- Bad, because a target the stop node post-dominates but the split does not dominate is walked inline by the chain all the same, the way the guard clause walks it, so a target reached from elsewhere leaves its other edges as jumps.
- Bad, because "tail" for a synthesized end is decidable only after the block's passes, so the emitter carries a deferred list and a resolve step that a reader has to find.
- Bad, because the decompiler always produces parseable source but not always source that validates, and not every edge survives.
-- Bad, because a modeller's document with a default-named plain end that is not last prints a reserved id and is refused until renamed, and the import-side label warning can only name the two outcomes rather than the one that will happen.
+- Bad, because a modeller's document with a default-named plain end that is not last, or that carries a label, prints a reserved id and is refused until renamed, and the import-side documentation warning can only name the two outcomes rather than the one that will happen.
- Bad, because a step whose routes merge at a merge of another kind prints jumps under a marker where an `if` chain would read better, that chain being a choice the model is not.
- Bad, because a branch that ends inside a loop body, a `do { end } while`, a loop gateway the compiler leaves without an incoming flow, and a post-test loop whose body ends inside a branch still print as jumps or markers, the last of them a jump the validator refuses; these are reported and pinned as they are.
diff --git a/docs/decisions/0021-operaton-engine-attributes-as-named-ir-fields.md b/docs/decisions/0021-operaton-engine-attributes-as-named-ir-fields.md
index cd287eb..81dc2c9 100644
--- a/docs/decisions/0021-operaton-engine-attributes-as-named-ir-fields.md
+++ b/docs/decisions/0021-operaton-engine-attributes-as-named-ir-fields.md
@@ -72,7 +72,7 @@ The printer lifts the three back into the `on timer` head as long as the start p
Every other host-less handler writes its settings on the event sub-process.
The process header's settings follow the same naming rule, and `historyTimeToLive` is the one with a default.
-`HistoryTimeToLiveParser.parseAndValidate` refuses a process without one under the engine's default `enforceHistoryTimeToLive`, so `irToXml` writes `P30D` when the IR names none, and the importer reads exactly that value back as absent to keep the round trip stable.
+`HistoryTimeToLiveParser.parseAndValidate` refuses a process without one under the engine's default `enforceHistoryTimeToLive`, so a script without one lowers to `P30D`, `irToXml` writes `P30D` for an imported process that names none, and the printer leaves exactly that value out of the script.
An imported document that sets none is warned about, since its rebuilt process deploys where the source did not.
`isStartableInTasklist` is the one that takes a boolean, and the importer reads it as `BpmnParse.isStartable` does, so any value but a case-insensitive `true` imports as `false`.
diff --git a/docs/decisions/0022-repetition-the-for-clause-and-its-per-run-job-settings.md b/docs/decisions/0022-repetition-the-for-clause-and-its-per-run-job-settings.md
index 3a133e5..9f02420 100644
--- a/docs/decisions/0022-repetition-the-for-clause-and-its-per-run-job-settings.md
+++ b/docs/decisions/0022-repetition-the-for-clause-and-its-per-run-job-settings.md
@@ -53,7 +53,7 @@ An element variable is optional with a collection, since `for each in batches` d
The whole construct is one optional field on the shape the activity nodes already share, so it reaches every kind without adding an arm to any exhaustive switch in the transform.
`runAsyncBefore`, `runAsyncAfter`, `runExclusive`, and `runRetryCycle` sit in the same parens a repeated statement's own five settings already occupy, each spelled by `runSettingKey(key) = prefixedSettingKey('run', key)`, the same function a join gateway's spellings use with a different prefix.
-There is no `runJobPriority`: `createActivityOnScope` reads a job priority off the activity element alone, and `parseActivity` swaps the scope to the multi-instance body before `createActivityOnScope` stores it, so a repeated step's plain `jobPriority` already prices each run's job.
+There is no `runJobPriority`, because `createActivityOnScope` reads a job priority off the activity element alone and a repeated step's plain `jobPriority` already prices each run's job ([ADR-0013](0013-validator-mirrors-parse-time-rules.md)).
No statement kind that repeats also synthesizes a gateway, so a `run`-prefixed key and a `join`-prefixed key never both sit in one parens.
On the XML side the loop element carries the plain, unprefixed attribute names, since it is already its own element, distinct from the activity's, and only the DSL surface needs a prefix where the step's settings and the loop's share one parens.
diff --git a/docs/decisions/0023-event-roots-from-usage-and-declared-codes.md b/docs/decisions/0023-event-roots-from-usage-and-declared-codes.md
index 9861740..b96d66c 100644
--- a/docs/decisions/0023-event-roots-from-usage-and-declared-codes.md
+++ b/docs/decisions/0023-event-roots-from-usage-and-declared-codes.md
@@ -63,7 +63,7 @@ Root ids are sanitized from the code and de-collided against the rest of the doc
The name and the code both reach BPMN, `@name` holding the declared name and `errorCode` or `escalationCode` holding the code, and they are the same text wherever the code is identifier-shaped.
`operaton:errorMessage` lives on the root rather than at the throw site, because two throws sharing a code share one root and a message at the throw site would need a mechanism to reconcile disagreeing copies.
-Import reads the pair back off each root, taking the root's `name` where a declaration can be written with it and minting one from the code otherwise (`claimDeclarationName`, `packages/transform/src/synthesize-ids.ts`), so a root nothing raises imports as a declaration nothing uses.
+Import reads the pair back off each root, taking the root's `name` as written, in backticks where it is no plain name, and the code where the root has none (`claimDeclarationName`, `packages/transform/src/synthesize-ids.ts`), so a root nothing raises imports as a declaration nothing uses.
An imported document whose two roots share a code but disagree on the message is refused rather than merged, since collapsing them would change what a throw carries at runtime.
The reference sits on `VarRef` rather than on an alternative of its own, and this was measured against the grammar rather than reasoned about: the parser cannot separate `error(OUT_OF_STOCK)` from `condition(ready)`, since both are one identifier inside the same `SettingsParens`.
@@ -75,14 +75,14 @@ Outside a code position the link fails by design, and `BpmnScriptDocumentValidat
Throw and emit decide terminality by keyword, not by position, so `throw` always ends its path and `emit` always continues into whatever follows it.
A single verb whose compiled form depends on being last in its block looks appealing, one fewer keyword, but it does not survive the round trip.
Take an IR shape the importer must be able to reproduce, a branch that fires an escalation and rejoins the main flow, `split -> A -> escalation-intermediate-throw -> join`.
-Printed inside its branch block, that statement is the last statement of the block simply because the branch has nothing after it, not because the event ends anything.
+Printed inside its branch block, that statement is the last statement of the block only because the branch has nothing after it, not because the event ends anything.
A position-decided desugarer reads "last in block", turns the statement back into an escalation end event on the way in, and drops the join edge the original graph had, so the same printed text would mean two different graphs depending on information the text itself does not carry.
`throw` also matches the intuition every reader brings from exception handling in a general-purpose language, and both escalation forms, end event and intermediate throw, stay independently printable.
`emit` is a general continuing verb, not an escalation-specific one, so error, which has no continuing BPMN form, has no `emit`, and later event kinds that fire and continue reuse the same verb instead of growing their own.
Giving every kind its own throw-and-continue verb turns the surface into a vocabulary quiz.
-Trigger kinds and binding fields are validated identifiers, not keywords: `on`, `throw`, `emit` and `alongside` are the only words this event layer reserves.
+Trigger kinds and binding fields are validated identifiers, not keywords: `on`, `throw`, `emit`, `alongside` and `await` ([ADR-0026](0026-intermediate-catch-events.md)) are the only words the event layer reserves.
The reason is the audience, not parsing convenience.
`message` and `code` are two of the most ordinary variable names in Java-style code, and a Langium keyword is lexer-global, so there is no way to reserve a word only inside `on`, `throw` and `emit` and leave it free everywhere else.
What a keyword gives away for free is rebuilt explicitly, each part in the mechanism meant for it: a validator checks each word against its small legal set and names the options directly in the diagnostic, a semantic-token provider marks exactly the AST properties that carry meaning, so `on error` highlights `error` while `var error` stays plain, and completion items are offered at the same positions.
diff --git a/docs/decisions/0024-event-trigger-payloads-paren-slot.md b/docs/decisions/0024-event-trigger-payloads-paren-slot.md
index 4a99baa..8c361f7 100644
--- a/docs/decisions/0024-event-trigger-payloads-paren-slot.md
+++ b/docs/decisions/0024-event-trigger-payloads-paren-slot.md
@@ -15,7 +15,7 @@ Timer carries something different: a word choosing which of BPMN's three timer f
Conditional carries a boolean expression, which wants the same parenthesized slot error/escalation already use for bindings, but for an unrelated purpose: a condition, not a catch parameter.
Fitting three payload shapes into one handler surface, without forking `on` into a separate grammar rule per trigger kind and without reserving a new keyword for each shape, is the central question this decision resolves.
-Two narrower questions ride along with it: how a timer's payload text becomes one of BPMN's three timer definition kinds without silently picking the wrong one, and how much of BPMN's conditional-evaluation narrowing the surface should expose given that the DSL's audience has no reason to know it exists.
+Two narrower questions ride along with it: how a timer's payload text becomes one of BPMN's three timer definition kinds without picking the wrong one unnoticed, and how much of BPMN's conditional-evaluation narrowing the surface should expose given that the DSL's audience has no reason to know it exists.
## Decision Drivers
@@ -33,11 +33,11 @@ Two narrower questions ride along with it: how a timer's payload text becomes on
- A binding-marker keyword freeing the parens for bindings only, writing them after a marker such as `as (...)`, which spends a new reserved word on a collision structural lookahead already dissolves for free and breaks the parameter-list reading (`on error(X, code: c, message: m)`, read like `catch (Exception e)`) that motivated the binding shape in the first place.
- A string-wrapped condition, written as a quoted literal instead of a real expression, which reads worse than the language's own `if (...)` and throws away everything a real expression AST buys, including undeclared-variable checking, type checking, symbol participation, and precise highlighting.
- Reserving `condition` as a keyword to dispatch the parens, which would be a lexer-global reservation, unusable as an ordinary variable name anywhere in a file, for exactly the reason the trigger and binding words already stay soft identifiers.
-- Timer particles, a bare string for a duration and the keys `at` and `every` for a date and a cycle, as validated identifiers mapping one-to-one to BPMN's three timer forms, which read as the English they mean and cannot silently resolve to the wrong form.
+- Timer particles, a bare string for a duration and the keys `at` and `every` for a date and a cycle, as validated identifiers mapping one-to-one to BPMN's three timer forms, which read as the English they mean and cannot resolve to the wrong form unnoticed.
- A single particle with the timer form inferred from the value's shape, where an ISO date looks like a date and a duration string looks like a duration, which shifts a scheduling decision onto pattern-matching the value's text: a mistyped ISO string, or an expression the engine evaluates at runtime rather than a literal the compiler can inspect, becomes a different timer kind than the one the author meant, with no diagnostic pointing at the mismatch.
- Deferring the conditional narrowing attributes and refusing them on import rather than dropping them.
- Surfacing them as a fourth payload shape, narrower than the other three and carrying nothing but an engine-side optimization hint the audience has no reason to know about.
-- Dropping them silently on import, which would leave the imported process re-checking its condition on every variable change instead of the one the original author scoped it to.
+- Dropping them on import without a word, which would leave the imported process re-checking its condition on every variable change instead of the one the original author scoped it to.
- Message and signal roots derived from usage, keyed by name, with no declaration form, since the name is both the root's only data and its key.
- An explicit root declaration mirroring the error message declaration, which generalizes a mechanism that exists only because the error message text has no other source to two triggers for which usage already supplies every property in full.
@@ -73,4 +73,4 @@ A message or signal name has neither need, so no declaration form is introduced
- Good, because the condition payload stays a real, checkable expression rather than an opaque string, so a condition handler gets the same variable checking, symbol participation, and highlighting an `if` statement already gets.
- Bad, because a document carrying the conditional narrowing attributes cannot be imported at all, even though the underlying evaluation difference is invisible to a reader who does not already know Camunda's narrowing mechanism exists.
The refusal is correct but reads as stricter than the visible difference suggests.
-- Bad, because timer's three particles are one more small vocabulary to learn than a single particle would have been, paid once in exchange for a scheduling decision that cannot silently resolve to the wrong timer kind.
+- Bad, because timer's three particles are one more small vocabulary to learn than a single particle would have been, paid once in exchange for a scheduling decision that cannot resolve to the wrong timer kind unnoticed.
diff --git a/docs/decisions/0025-events-at-the-process-boundary.md b/docs/decisions/0025-events-at-the-process-boundary.md
index 25a5504..174a496 100644
--- a/docs/decisions/0025-events-at-the-process-boundary.md
+++ b/docs/decisions/0025-events-at-the-process-boundary.md
@@ -69,7 +69,7 @@ Neither clause needs a new reserved word.
Nothing else can appear there, because every statement in this grammar is keyword-led, and both rules were built into a live Langium parser with Chevrotain's self-analysis on, which reported no ambiguity.
`terminate` and the four start words therefore stay soft identifiers, and `var terminate: string` parses beside `end Done terminate`.
-The attributes that make the engine really send a thrown message, `operaton:class`, `expression`, `delegateExpression`, `type`, `topic`, and an `` child, are read off the `bpmn:messageEventDefinition`, which is the surface the task kinds carry; the same attributes on the event element itself are inert.
+A thrown message carries the implementation that makes the engine send it on its `bpmn:messageEventDefinition`, as [ADR-0016](0016-task-kinds-on-the-authoring-surface.md) records.
A `start` opens a chain and takes no incoming flow, so it may sit first in the process body, directly after another `start`, or after a statement whose flow always ends or redirects, and a start after a step whose flow is still live is refused with a message naming the fix, because either reading of that page invents a flow the author did not write.
That freedom holds for a process body only: an embedded `subprocess`, an `attempt` block, and an event-handler body keep exactly one start, at their head, because `parseScopeStartEvent` rejects the second start of any scope that is not a process definition, and a second start in one of them is refused on import by count (`checkStartEventCount`, `packages/transform/src/xml-to-ir.ts`), naming that engine reason, while a process is let through.
diff --git a/docs/decisions/0026-intermediate-catch-events.md b/docs/decisions/0026-intermediate-catch-events.md
index cbc5040..f529bf3 100644
--- a/docs/decisions/0026-intermediate-catch-events.md
+++ b/docs/decisions/0026-intermediate-catch-events.md
@@ -31,7 +31,7 @@ Three questions settle together: what word introduces it, given that trigger wor
## Decision Outcome
Chosen options: `await`, a name that follows the trigger word rather than preceding it, and a scope of message, timer, signal, and conditional.
-Link joins that scope for the import direction (ADR-0030).
+Link joins that scope as well, for a reason of its own ([ADR-0030](0030-link-events-for-import-round-trip-symmetry.md)).
Before committing to the keyword, the rule was built into a live Langium parser with Chevrotain's self-analysis switched on (`createServicesForGrammar`) and the full trigger-payload battery was run through it.
Every form parsed with zero ambiguity warnings, including the case that matters: `await timer("PT1H")`, a bare identifier followed by a parenthesized payload, resolved to `trigger='timer'` with the duration as its payload.
diff --git a/docs/decisions/0028-compensation-as-subprocess-undo-block.md b/docs/decisions/0028-compensation-as-subprocess-undo-block.md
index dfc7c9e..4a87dd4 100644
--- a/docs/decisions/0028-compensation-as-subprocess-undo-block.md
+++ b/docs/decisions/0028-compensation-as-subprocess-undo-block.md
@@ -20,7 +20,7 @@ The question this decision settles is which of BPMN's two attachment shapes, or
- The engine restricts one of the two BPMN attachment forms, the compensation event sub-process, to embedded sub-processes and one per level; a surface that treats both forms as equally general everywhere would produce documents the engine does not support.
- The audience writes processes without BPMN vocabulary already established for `on`/`throw`/`emit`; a second attachment mechanism, boundary event, association, and a normally-dormant activity, for one event kind breaks the pattern every other trigger kind follows.
- `waitForCompletion="false"` and `activityRef`-targeted throws only matter in combination with boundary-attached handlers; neither has a use once boundary handlers are out of scope.
-- The honest import contract (ADR-0012) already distinguishes constructs the DSL refuses from ones it silently drops; a construct this decision does not model needs to land on one side of that line, not the other.
+- The honest import contract (ADR-0012) already distinguishes constructs the importer refuses from ones it drops with a warning; a construct this decision does not model needs to land on one side of that line, not the other.
## Considered Options
@@ -31,7 +31,7 @@ The question this decision settles is which of BPMN's two attachment shapes, or
## Decision Outcome
-Chosen option: "Compensation handlers exist only as a subprocess's `on compensation` block, thrown with the existing `throw`/`emit` pair and no code", because it keeps compensation inside the vocabulary the rest of the event layer already uses, and the rejected alternatives either duplicate a granularity the subprocess construct already provides or only pay for themselves once that duplication exists.
+Chosen option: "Compensation handlers only as a subprocess's `on compensation` block", because it keeps compensation inside the vocabulary the rest of the event layer already uses, and the rejected alternatives either duplicate a granularity the subprocess construct already provides or only pay for themselves once that duplication exists.
An undo block lowers to a `bpmn:subProcess triggeredByEvent="true"` nested inside the `bpmn:subProcess` it undoes, whose start event carries a `compensateEventDefinition`.
The at-most-one rule and the container rule are the engine's own restriction rather than a choice of this surface, and a process has no completed enclosing scope to reverse, so `on compensation` at process level is rejected rather than approximated.
@@ -58,7 +58,7 @@ BPMNscript reaches the same granularity without a second mechanism: wrapping the
### Confirmation
-Round-trip coverage in `packages/transform/test` pins an undo block lowering to a nested `triggeredByEvent` sub-process with exactly one `compensateEventDefinition`-carrying start event, `throw compensation` and `emit compensation` lowering to a compensation end event and a compensation intermediate throw without an `activityRef`, and each of the four refused shapes producing a distinct refusal rather than a silently altered import.
+Round-trip coverage in `packages/transform/test` pins an undo block lowering to a nested `triggeredByEvent` sub-process with exactly one `compensateEventDefinition`-carrying start event, `throw compensation` and `emit compensation` lowering to a compensation end event and a compensation intermediate throw without an `activityRef`, and each of the four refused shapes producing a distinct refusal rather than an altered import.
`packages/language/test/validating.test.ts` pins the container rule, including the rejection of a second undo block in one `subprocess` or one `attempt`.
Two suites under `tests/e2e/` deploy to a real Operaton and confirm that an undo block executes on a running engine rather than only lowering to the right shape: an `emit compensation` raised by a process-level error handler reaching the undo block of a subprocess that had already completed, and a completed subprocess's undo steps running once the `attempt` block around it is given up.
diff --git a/docs/decisions/0029-work-that-can-be-given-up.md b/docs/decisions/0029-work-that-can-be-given-up.md
index c6b1328..69e709e 100644
--- a/docs/decisions/0029-work-that-can-be-given-up.md
+++ b/docs/decisions/0029-work-that-can-be-given-up.md
@@ -10,7 +10,7 @@ decision-makers: Marlon Kranz
BPMN has a container for work abandoned as a unit: a `bpmn:transaction`, given up by an end event inside it carrying a `bpmn:cancelEventDefinition`, caught by a boundary event of the same kind.
Operaton rejects either cancel position outside such a container, so neither is expressible until the container is.
-This grammar had no container to put them in, so any document carrying the element refused on import and the round trip stopped there.
+Without a container to put them in, any document carrying the element refuses on import and the round trip stops there.
The question this decision settles: what does the container head say, where may a cancel sit, and which shapes does the surface decline to carry?
## Decision Drivers
@@ -51,7 +51,7 @@ A handler on a block whose body holds no cancel end warns for the same reason, s
### Consequences
-- Good, because a document the engine runs as work that can be given up now imports, prints, and recompiles byte for byte, where before it stopped the import at the container.
+- Good, because a document the engine runs as work that can be given up imports, prints, and recompiles byte for byte.
- Good, because a block written with the new head and carrying no cancel anywhere is an ordinary block of work to the engine, which is what lets an imported transaction round-trip unchanged.
- Good, because such a block may carry its own `on compensation`, so an enclosing scope can undo it in turn: Operaton's `CompensationUtil.hasCompensationEventSubprocess` asks only whether the handler is a sub-process scope triggered by an event, never what tag the block it undoes carries.
- Neutral, because giving up a block undoes the finished work of every child inside it that carries an undo block, and reaches nothing around it.
diff --git a/docs/decisions/0030-link-events-for-import-round-trip-symmetry.md b/docs/decisions/0030-link-events-for-import-round-trip-symmetry.md
index fe33c1f..88f4255 100644
--- a/docs/decisions/0030-link-events-for-import-round-trip-symmetry.md
+++ b/docs/decisions/0030-link-events-for-import-round-trip-symmetry.md
@@ -8,16 +8,16 @@ decision-makers: Marlon Kranz
## Context and Problem Statement
-BPMNscript's `await` trigger scope covers message, timer, signal, and conditional, and leaves link out: BPMN's off-page connector for splitting one diagram across pages, a problem a single `.bpmnscript` file never has, since `goto` already names a jump inside one textual source.
-That choice holds for authoring, but it says nothing about import.
-A modeller's existing document can carry a link pair, and the importer refuses `bpmn:linkEventDefinition` by name on both the intermediate throw and the intermediate catch, so such a document does not import at all.
+Authoring gives `await` no reason to take a link trigger beside message, timer, signal, and conditional ([ADR-0026](0026-intermediate-catch-events.md)): a link is BPMN's off-page connector for splitting one diagram across pages, a problem a single `.bpmnscript` file never has, since `goto` already names a jump inside one textual source.
+That argument holds for authoring, but it says nothing about import.
+A modeller's existing document can carry a link pair, and without a construct for it the importer has to refuse `bpmn:linkEventDefinition` on both the intermediate throw and the intermediate catch, so such a document does not import at all.
Reading a link pair as a `goto` would not fix this under the honest import contract (ADR-0012), which lets the importer warn on a drop that changes nothing the engine runs but never lets it rewrite what is on the wire into a shape the surface prefers: a `goto` compiles to one sequence flow, so the re-exported XML would hold one edge where the incoming document held two events.
The question this decision settles is whether a construct authoring does not need should exist anyway, for better import coverage of existing models and round-trip symmetry.
## Decision Drivers
- Import coverage of existing models.
- Modelers built on bpmn-js, the Camunda Modeler among them, offer both ends of a link pair, and a document drawn with one is refused today.
+ Modelers built on bpmn-js, the Camunda Modeler among them, offer both ends of a link pair, and a document drawn with one should import.
- Round-trip symmetry under ADR-0012.
A construct the importer maps has to re-export as the same XML, and a link pair mapped to a `goto` does not.
- Reuse of what is built.
@@ -29,7 +29,7 @@ The question this decision settles is whether a construct authoring does not nee
## Considered Options
-- Keep refusing a link definition on import, which adds no grammar rule, no vocabulary row, and no second way to jump, but leaves every diagram using BPMN's own off-page connector unimportable, on a refusal the import contract does not ask for, since the engine deploys and runs a link pair.
+- Refuse a link definition on import, which adds no grammar rule, no vocabulary row, and no second way to jump, but leaves every diagram using BPMN's own off-page connector unimportable, on a refusal the import contract does not ask for, since the engine deploys and runs a link pair.
- Import a link pair as a `goto`, and never author one, which changes the authoring surface not at all and shows the reader a jump in the form this language already has, but re-exports two events and their definitions as one edge, which round-trip symmetry rules out by construction, and leaves the printer deciding which `goto` edges were links from a fact the IR no longer holds.
- A full surface, `emit link` and a named `await link`, which maps one-to-one in both directions and reuses the payload surface, the required-name check, and the completion snippet message and signal already have, at the price of two constructs for one jump and a name slot on every `await` to make one kind of `await` nameable.
@@ -43,7 +43,7 @@ This is the one `emit` whose chain ends; the two printed words `emit link` decid
The link name is quoted text, `link("Retry")`, like a message or signal name.
It keys the engine's own table and declares nothing, so it is not a declared code in the sense ADR-0023 gives error and escalation.
-`await` gains the optional name slot `emit` has, legal on every trigger rather than on a link catch alone, because a link catch has to be nameable to keep its id across an import and a link-only slot would need a validator rule with no engine reason behind it.
+`await` takes the optional name slot `emit` has, legal on every trigger rather than on a link catch alone, because a link catch has to be nameable to keep its id across an import and a link-only slot would need a validator rule with no engine reason behind it.
In the IR both ends carry `{ kind: 'link'; linkName: string }` and no flow runs between them.
The precedent is `BoundaryEvent.attachedToRef`, a node with no incoming flow wired to another by a reference rather than by an edge, not `SubProcess.element`, which is a tag on one node with no graph consequence.
@@ -70,7 +70,7 @@ That is why the argument for this surface is notation fidelity and not execution
- Good, because a document carrying a link pair imports instead of being refused, and it re-exports as the same two events under the same name, which the honest import contract (ADR-0012) requires and a `goto` rewrite cannot give.
- Good, because link costs one dispatch case per layer: a fifth catch kind on the payload surfaces of ADR-0024, one `case 'link'` in each direction of the transform, and one row in the trigger vocabulary.
-- Good, because every `await` is now nameable, so an author can `goto` a specific wait.
+- Good, because every `await` is nameable, so an author can `goto` a specific wait.
- Bad, because two constructs now spell one jump, and a reader who meets `emit link` has to be told it is a `goto` in the diagram's own notation.
- Bad, because `emit` is no longer always continuing; `emit link` is the one form that ends its chain, read off the trigger word.
- Bad, because link names are unique per file where a `goto` target is unique per container, so two subprocesses cannot each have a link called `Retry`.
diff --git a/docs/decisions/0031-inclusive-and-event-based-gateways.md b/docs/decisions/0031-inclusive-and-event-based-gateways.md
index 2549412..c3a8c6a 100644
--- a/docs/decisions/0031-inclusive-and-event-based-gateways.md
+++ b/docs/decisions/0031-inclusive-and-event-based-gateways.md
@@ -1,6 +1,6 @@
---
status: accepted
-date: 2026-08-30
+date: 2026-10-17
decision-makers: Marlon Kranz
---
@@ -17,6 +17,10 @@ So the question is not which keyword spells "inclusive gateway".
It is whether block structure can express the intent well enough that the compiler still picks the element, and which of the flows out of such a fork are worth writing.
A gateway's `name` survives XML to IR to XML, then dies at the print hop, where no gateway has a statement form to carry it (`normalizeContainer`, `tests/helpers/normalize-ir.ts`).
+A split can also stop the run on purpose.
+`ExclusiveGatewayActivityBehavior.doLeave` and `InclusiveGatewayActivityBehavior.execute` throw `ENGINE-02004 No outgoing sequence flow for the element with id '...' could be selected for continuing the process` when no flow is taken and none is the default, and a step whose routes are all conditioned throws `ENGINE-02006` (`BpmnActivityBehavior.handleNoTransitions`).
+A variant of the Operaton invoice example whose approval split names no default is one such model, and a script needs a way to say it.
+
## Decision Drivers
- ADR-0006 binds two rules: a keyword names what the user means rather than the BPMN element, and the compiler must not require what it can infer.
@@ -27,6 +31,8 @@ A gateway's `name` survives XML to IR to XML, then dies at the print hop, where
- The tool's own output should print back as source the validator accepts.
- Trigger words are soft identifiers by design (ADR-0023), so a rule proves nothing until a live parser accepts it.
- A label dropped on the way out needs a channel to be reported through, and ADR-0012's contract covers `xmlToIr` only.
+- The engine's no-match failure is not a BPMN error: no error boundary or `on error` handler catches it.
+- A new reserved word costs authors a name, and a variable has no backtick form to win it back.
## Considered Options
@@ -44,6 +50,10 @@ A gateway's `name` survives XML to IR to XML, then dies at the print hop, where
- For the gateway label, no slot, with the print-side drop reported through a warnings channel out of `irToDsl`, which keeps every gateway elided and puts the label on the same channel as the print hop's other reports, at the cost of a signature change.
- For the gateway label, a slot on `if`, `while`, `parallel`, and the two new forms, which is the only way a label survives a full BPMN to DSL to BPMN round trip, but a labeled gateway is an authored gateway.
- For the gateway label, no slot and a silent drop, which costs nothing, and is the one thing ADR-0012's contract exists to prevent.
+- For a split that fails when no condition holds, a closing `else fail` on an `if` chain and on a `parallel` block, with `fail` a soft word legal only after `else`.
+- The same form with `fail` a reserved word, which the TextMate grammar would colour for free, but it would take `var fail` and `user fail` out of the language.
+- `else throw`, which reads as an error, but `throw` already raises a BPMN error that a handler can catch, and this failure cannot be caught.
+- No form for that split, and a warning on import, which leaves every such import changing what runs.
- A `gateway` keyword, or a flat node-and-edge escape hatch, which would express every gateway shape, but a gateway that prints re-parses with an authored id.
## Decision Outcome
@@ -53,10 +63,18 @@ Nothing in the surface names a gateway, and ADR-0010's positional ids keep worki
Every form below parsed with zero ambiguity warnings in a live Langium parser with Chevrotain self-analysis on.
A branch of a `parallel` block may be headed by `if (condition)`, by `else`, or by nothing at all, and the compiler picks the element from what the branches carry rather than from the keyword.
-Operaton takes every non-default flow that has no condition or a true one, and adds the default only when that set comes out empty (`InclusiveGatewayActivityBehavior.execute`), so `lowerParallel` reserves `Flow__default` only where the engine can take it: beside an `else`, or, when every branch carries a condition, running straight to the join, the rule `lowerIf` already applies at the same position, since such a fork with no default deploys, runs, then throws a stuck execution the first time no condition holds.
+Operaton takes every non-default flow that has no condition or a true one, and adds the default only when that set comes out empty (`InclusiveGatewayActivityBehavior.execute`), so `lowerParallel` reserves `Flow__default` only where the engine can take it: beside an `else`, or, when every branch carries a condition and the block does not close with `else fail`, running straight to the join, the rule `lowerIf` applies at the same position.
Beside a branch carrying no condition that branch is in the taken set every time, so the set never comes out empty, a fallback behind it could never run, and an `else` written there is refused for the same reason.
All of this is a lowering rule rather than a validator rule because `BpmnParse.parseInclusiveGateway` validates nothing.
+A split that stops the run when no condition holds closes with `else fail`, and `fail` is a soft word legal only there, so it stays a legal variable and step name.
+`lowerIf` reserves no default flow for it and `lowerParallel` adds no fallback to the join, so the compiled split carries only its conditioned flows and the engine stops the run exactly as the imported model did.
+The printer writes `else fail` for every exclusive or inclusive split, gateway or step, whose model routes are all conditioned and that names no default, except a fork that degrades to jumps, whose chain of jumps closes without it.
+An `if` chain is conditioned on every branch by its shape, so `else fail` is always legal there.
+On a `parallel` block the validator refuses it with no conditioned branch, beside an unconditioned branch, which always runs, and beside an `else` branch, which runs whenever no condition holds, the same reasons it refuses an `else` in those places.
+A loop takes no `else fail`, because the route out of a `while` or `do ... while` is its fallback, and the remaining exits of a loop head print as an `if` chain that takes `else fail` like any other.
+Beside `else fail` an empty conditioned branch is how a case carries on rather than failing, so it draws no empty-branch warning.
+
Every fall-through carries the reserved exit id, the back-edge included.
`lowerWhile` wires its back-edge with `body.exitFlowId`, as `lowerDoWhile` does, so a `while` whose body ends in a loop keeps that loop's declared default on the flow the enclosing head takes and `irToXml` accepts the document.
@@ -94,11 +112,14 @@ Neither that shape nor the one Operaton refuses is authorable, so the extra widt
- Good, because neither construct spends a reserved word; reserving `race` would take `var race: string` and `user race` out of the language.
- Good, because a compiled inclusive fork beside an unconditioned branch prints back without a warning and re-parses without an error.
- Good, because a `while` whose body ends in a loop compiles.
+- Good, because an imported split whose routes are all conditioned and that names no default rebuilds unchanged, the invoice variant included.
- Bad, because a conditioned `parallel` reads as one construct but compiles to either of two BPMN elements, so a BPMN-literate reader must read every branch.
- Bad, because `irToDsl` changes its return shape, touching every call site, and the drop that motivated it costs the reader a gateway's name rather than anything the process does.
- Bad, because the label comes back on a BPMN-to-BPMN pass but never on a BPMN-to-DSL one, so a decompiled and recompiled document loses every gateway label.
- Bad, because a conditional branch of a race can win without waiting (`EventBasedGatewayActivityBehavior.execute`), which no part of the surface shows.
- Bad, because an inclusive fork closed on an exclusive merge, the common hand-drawn shape, degrades to `goto`s a reader repairs by hand.
+- Bad, because an imported split whose routes do not meet again prints its continuing route as an empty `else if` branch rather than as a fall-through.
+- Bad, because the soft word `fail` needs its own highlighting rule in the TextMate grammar and a test that pins it to the vocabulary.
- Bad, because a join that exactly one flow reaches stays in the document, where bpmnlint reports it as superfluous and the auto-layout draws the default edge into it across the terminating branch's end event.
### Confirmation
@@ -107,6 +128,9 @@ Neither that shape nor the one Operaton refuses is authorable, so the extra widt
`packages/transform/test/` pins element selection, the four fallback shapes in one table, the nested `while` with the reserved id on its back-edge through `irToXml`, the race's join and its pruning, the inclusive carry, each refusal by name, elision of both new pairs, the dropped-label warning reaching the caller, and a modeled fallback running straight into the merge coming back as the model without that edge.
The frozen pairs `tests/golden/branch-and-race.{bpmnscript,bpmn}` and `tests/golden/gateway-settings.{bpmnscript,bpmn}` each hold an inclusive fork beside an unconditioned branch with no `default` attribute, asserting IR idempotence after normalization and that the decompiled source recompiles cleanly, and a Docker-gated end-to-end test shows the losing race branch canceled and the inclusive join waiting for exactly the branches taken.
+`packages/language/test/` also pins both `else fail` heads, each of its validator rules, its completion after `else` and the highlighting of `fail`.
+`tests/else-fail.round-trip.test.ts` pins that an imported exclusive and inclusive split with no default prints as `else fail` and compares with no differences and no warning, and `tests/e2e/claim-routing.test.ts` runs `examples/spring-boot/processes/claim-routing.bpmnscript` on Operaton, where a holding condition runs its route and with none holding both the start request and the task completion before the inclusive fork fail with `ENGINE-02004`.
+
## More Information
Operaton behavior was read from `BpmnParse.java`, `InclusiveGatewayActivityBehavior.java`, `ExclusiveGatewayActivityBehavior.java` and `EventBasedGatewayActivityBehavior.java` in the `operaton/operaton` repository.
diff --git a/docs/decisions/README.md b/docs/decisions/README.md
index 88f587e..9240da4 100644
--- a/docs/decisions/README.md
+++ b/docs/decisions/README.md
@@ -3,39 +3,40 @@
Each file in this directory records one design decision behind BPMNscript: the problem, the options weighed, the choice, and what it costs.
Every record follows the MADR shape in [adr-template.md](adr-template.md), and states the decision as it stands today.
Where a record names what the engine does, that behaviour was read from Operaton 2.1.0.
+The syntax a record mentions is taught in full in the [language reference](../../packages/language/README.md).
-| Number | Title | Status |
-| ---------------------------------------------------------------------- | ------------------------------------------------------------------- | -------- |
-| [0000](0000-use-markdown-architectural-decision-records.md) | Use Markdown Architectural Decision Records | accepted |
-| [0001](0001-use-apache-2-license.md) | Use Apache 2.0 License | accepted |
-| [0002](0002-use-mono-repo-structure.md) | Use Mono-repo Structure | accepted |
-| [0003](0003-use-langium-as-language-workbench.md) | Use Langium as Language Workbench | accepted |
-| [0004](0004-use-vscode-as-primary-ide-target.md) | Use VS Code as Primary IDE Target | accepted |
-| [0005](0005-in-editor-conversion-webview-sidebar.md) | In-Editor Conversion: Webview Sidebar and Two Layers | accepted |
-| [0006](0006-target-users-without-bpmn-knowledge.md) | Target users without BPMN knowledge, and minimize boilerplate | accepted |
-| [0007](0007-intermediate-representation-ast-bpmn.md) | An intermediate representation between the AST and BPMN XML | accepted |
-| [0008](0008-fork-camunda-moddle-extension.md) | Fork the Camunda moddle extension as a local Operaton one | accepted |
-| [0009](0009-auto-layout-and-expansion-hint.md) | Diagram interchange: auto-layout and the sub-process expansion hint | accepted |
-| [0010](0010-deterministic-synthesized-ids.md) | Deterministic ids for synthesized elements, reserved and respelled | accepted |
-| [0011](0011-structured-grammar-one-bracket-shape.md) | A structured, code-like grammar with one bracket shape | accepted |
-| [0012](0012-honest-bpmn-import.md) | Honest BPMN import: refusals, warnings, and the parse tiers | accepted |
-| [0013](0013-validator-mirrors-parse-time-rules.md) | The validator mirrors the engine's parse-time rules | accepted |
-| [0014](0014-restructure-the-ir-into-a-dsl-with-dominator-analysis.md) | Restructure the IR into a DSL with dominator analysis | accepted |
-| [0015](0015-the-print-declares-every-variable-it-reads.md) | The print declares every variable it reads | accepted |
-| [0016](0016-task-kinds-on-the-authoring-surface.md) | Task kinds on the authoring surface | accepted |
-| [0017](0017-service-task-bindings.md) | Service task bindings, including external, mail and shell | accepted |
-| [0018](0018-forms-and-field-injection.md) | Forms and field injection | accepted |
-| [0019](0019-a-call-activitys-variable-mapping.md) | A call activity's variable mapping | accepted |
-| [0020](0020-listeners-reuse-on-inside-the-attribute-block.md) | Listeners reuse `on` inside the attribute block | accepted |
-| [0021](0021-operaton-engine-attributes-as-named-ir-fields.md) | Operaton engine attributes as named IR fields | accepted |
-| [0022](0022-repetition-the-for-clause-and-its-per-run-job-settings.md) | Repetition: the `for` clause and its per-run job settings | accepted |
-| [0023](0023-event-roots-from-usage-and-declared-codes.md) | Event root elements derived from usage, and declared codes | accepted |
-| [0024](0024-event-trigger-payloads-paren-slot.md) | Event trigger payloads in one paren slot | accepted |
-| [0025](0025-events-at-the-process-boundary.md) | Events at the process boundary: starts, ends and throws | accepted |
-| [0026](0026-intermediate-catch-events.md) | Intermediate catch events | accepted |
-| [0027](0027-boundary-events-attached-to-an-activity.md) | Boundary events attached to an activity | accepted |
-| [0028](0028-compensation-as-subprocess-undo-block.md) | Compensation as a subprocess undo block | accepted |
-| [0029](0029-work-that-can-be-given-up.md) | Work that can be given up: `attempt` and `cancel` | accepted |
-| [0030](0030-link-events-for-import-round-trip-symmetry.md) | Link events for import round-trip symmetry | accepted |
-| [0031](0031-inclusive-and-event-based-gateways.md) | Inclusive and event-based gateways | accepted |
-| [0032](0032-expressions-raw-templates-and-escapes.md) | Expressions: raw templates, escapes, and what is lowered as EL | accepted |
+| Number | Title | Status |
+| ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | -------- |
+| [0000](0000-use-markdown-architectural-decision-records.md) | Use Markdown Architectural Decision Records | accepted |
+| [0001](0001-use-apache-2-license.md) | Use the Apache 2.0 license | accepted |
+| [0002](0002-use-mono-repo-structure.md) | Use a mono-repo structure | accepted |
+| [0003](0003-use-langium-as-language-workbench.md) | Use Langium as the language workbench | accepted |
+| [0004](0004-use-vscode-as-primary-ide-target.md) | Use VS Code as the primary IDE target | accepted |
+| [0005](0005-in-editor-conversion-webview-sidebar.md) | In-editor conversion: a webview sidebar and two layers | accepted |
+| [0006](0006-target-users-without-bpmn-knowledge.md) | Target users without BPMN knowledge, and minimize boilerplate | accepted |
+| [0007](0007-intermediate-representation-ast-bpmn.md) | An intermediate representation between the AST and BPMN XML | accepted |
+| [0008](0008-fork-camunda-moddle-extension.md) | Fork the Camunda moddle extension as a local Operaton one | accepted |
+| [0009](0009-auto-layout-and-expansion-hint.md) | Diagram interchange: auto-layout and the sub-process expansion hint | accepted |
+| [0010](0010-deterministic-synthesized-ids.md) | Deterministic ids for synthesized elements, reserved, and authored ids kept as written | accepted |
+| [0011](0011-structured-grammar-one-bracket-shape.md) | A structured, code-like grammar with one bracket shape | accepted |
+| [0012](0012-honest-bpmn-import.md) | Honest BPMN import: refusals, warnings, and the parse tiers | accepted |
+| [0013](0013-validator-mirrors-parse-time-rules.md) | The validator mirrors the engine's parse-time rules | accepted |
+| [0014](0014-restructure-the-ir-into-a-dsl-with-dominator-analysis.md) | Restructure the IR into a DSL with dominator analysis | accepted |
+| [0015](0015-the-print-declares-every-variable-it-reads.md) | The print declares every variable it reads | accepted |
+| [0016](0016-task-kinds-on-the-authoring-surface.md) | Task kinds on the authoring surface | accepted |
+| [0017](0017-service-task-bindings.md) | Service task bindings, including external, mail and shell | accepted |
+| [0018](0018-forms-and-field-injection.md) | Forms and field injection | accepted |
+| [0019](0019-a-call-activitys-variable-mapping.md) | A call activity's variable mapping | accepted |
+| [0020](0020-listeners-reuse-on-inside-the-attribute-block.md) | Listeners reuse `on` inside the attribute block | accepted |
+| [0021](0021-operaton-engine-attributes-as-named-ir-fields.md) | Operaton engine attributes as named IR fields | accepted |
+| [0022](0022-repetition-the-for-clause-and-its-per-run-job-settings.md) | Repetition: the `for` clause and its per-run job settings | accepted |
+| [0023](0023-event-roots-from-usage-and-declared-codes.md) | Event root elements derived from usage, and declared codes | accepted |
+| [0024](0024-event-trigger-payloads-paren-slot.md) | Event trigger payloads in one paren slot | accepted |
+| [0025](0025-events-at-the-process-boundary.md) | Events at the process boundary: starts, ends and throws | accepted |
+| [0026](0026-intermediate-catch-events.md) | Intermediate catch events | accepted |
+| [0027](0027-boundary-events-attached-to-an-activity.md) | Boundary events attached to an activity | accepted |
+| [0028](0028-compensation-as-subprocess-undo-block.md) | Compensation as a subprocess undo block | accepted |
+| [0029](0029-work-that-can-be-given-up.md) | Work that can be given up: `attempt` and `cancel` | accepted |
+| [0030](0030-link-events-for-import-round-trip-symmetry.md) | Link events for import round-trip symmetry | accepted |
+| [0031](0031-inclusive-and-event-based-gateways.md) | Inclusive and event-based gateways | accepted |
+| [0032](0032-expressions-raw-templates-and-escapes.md) | Expressions: raw templates, escapes, and what is lowered as EL | accepted |
diff --git a/docs/decisions/adr-template.md b/docs/decisions/adr-template.md
index cf42613..e5f7187 100644
--- a/docs/decisions/adr-template.md
+++ b/docs/decisions/adr-template.md
@@ -1,6 +1,6 @@
---
# These are optional metadata elements. Feel free to remove any of them.
-status: '{proposed | rejected | accepted | deprecated | … | superseded by ADR-0123}'
+status: '{proposed | rejected | accepted | deprecated | ... | superseded by ADR-0123}'
date: { YYYY-MM-DD when the decision was last updated }
decision-makers: { list everyone involved in the decision }
consulted:
@@ -25,26 +25,26 @@ informed:
- {decision driver 1, for instance, a desired software quality, faced concern, constraint or force}
- {decision driver 2}
-- …
+- ...
## Considered Options
- {title of option 1}
- {title of option 2}
- {title of option 3}
-- …
+- ...
## Decision Outcome
-Chosen option: "{title of option 1}", because {justification. e.g., only option, which meets k.o. criterion decision driver | which resolves force {force} | … | comes out best (see below)}.
+Chosen option: "{title of option 1}", because {justification. e.g., only option, which meets k.o. criterion decision driver | which resolves force {force} | ... | comes out best (see below)}.
### Consequences
-- Good, because {positive consequence, e.g., improvement of one or more desired qualities, …}
-- Bad, because {negative consequence, e.g., compromising one or more desired qualities, …}
-- …
+- Good, because {positive consequence, e.g., improvement of one or more desired qualities, ...}
+- Bad, because {negative consequence, e.g., compromising one or more desired qualities, ...}
+- ...
@@ -60,7 +60,7 @@ Chosen option: "{title of option 1}", because {justification. e.g., only option,
-{example | description | pointer to more information | …}
+{example | description | pointer to more information | ...}
- Good, because {argument a}
- Good, because {argument b}
@@ -69,16 +69,16 @@ Chosen option: "{title of option 1}", because {justification. e.g., only option,
- Neutral, because {argument c}
- Bad, because {argument d}
-- …
+- ...
### {title of other option}
-{example | description | pointer to more information | …}
+{example | description | pointer to more information | ...}
- Good, because {argument a}
- Neutral, because {argument b}
- Bad, because {argument c}
-- …
+- ...
diff --git a/docs/glossary.md b/docs/glossary.md
index d75f13c..2524836 100644
--- a/docs/glossary.md
+++ b/docs/glossary.md
@@ -24,11 +24,11 @@ Terms that show up across the READMEs, the ADRs, and the code.
BPMNscript is a DSL for writing BPMN processes as text.
- **DI**: diagram interchange.
The `` part of a BPMN file that stores diagram coordinates, meaning where each box sits.
- BPMNscript regenerates it automatically on export; see [ADR-0009](decisions/0009-auto-layout-and-expansion-hint.md).
+ BPMNscript generates it on every compile and discards it on import ([ADR-0009](decisions/0009-auto-layout-and-expansion-hint.md)).
- **Multi-instance**: the BPMN marker that makes one activity run several times, once per element of a collection or a fixed number of times.
BPMNscript writes it from a `for` clause on the step; Operaton keeps the run counters on the repetition and a `loopCounter` on each run.
- **MIWG**: the Model Interchange Working Group.
- Its interoperability conventions, such as explicit ``/`` references on every node, are what Operaton expects in a BPMN file.
+ It publishes BPMN reference models and interchange conventions, such as explicit ``/`` references on every node, which the exporter follows.
## The toolchain
@@ -45,16 +45,16 @@ Terms that show up across the READMEs, the ADRs, and the code.
A small set of plain objects (`packages/transform/src/ir/types.ts`) that every transform reads from or writes to, in both directions.
See [ADR-0007](decisions/0007-intermediate-representation-ast-bpmn.md).
[ADR-0021](decisions/0021-operaton-engine-attributes-as-named-ir-fields.md) and [ADR-0020](decisions/0020-listeners-reuse-on-inside-the-attribute-block.md) extend that shape to the engine's execution settings, input/output parameters, and lifecycle listeners.
-- **Validator**: checks that a parsed process is structurally sound and reports errors in the editor.
+- **Validator**: checks the rules a parser can't express, such as types and engine constraints, and reports errors in the editor and the CLI.
The full list of checks is in [packages/language/README.md](../packages/language/README.md#diagnostics).
- **LSP**: Language Server Protocol.
The standard that lets one language server provide highlighting, autocompletion, and inline errors to any editor that speaks it.
- Langium implements it for us; the VS Code extension is the host.
+ Langium provides the server, and the VS Code extension hosts it.
- **moddle / bpmn-moddle**: the library that reads and writes BPMN XML as objects.
A _moddle extension_ (here, `operaton-moddle.json`) teaches it about the extra `operaton:` attributes, and about the nested types they can carry, such as an input/output value or a listener binding.
- Declaring those nested shapes is what lets an import warning attribute a dropped element to the specific step that carried it, instead of reporting an anonymous loss ([ADR-0021](decisions/0021-operaton-engine-attributes-as-named-ir-fields.md)).
+ Declaring the nested shapes lets an import warning name the step a dropped element sat on ([ADR-0021](decisions/0021-operaton-engine-attributes-as-named-ir-fields.md)).
- **Round trip**: compiling a `.bpmnscript` file to BPMN and decompiling the result back to `.bpmnscript`, or the reverse.
- Used to check what each hop keeps and what it warns about or drops.
+ The tests use it to check what each direction keeps, warns about, or drops.
## The repository
diff --git a/eslint.config.js b/eslint.config.js
index 8a081c8..8aa3b63 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -1,11 +1,8 @@
-import bpmnIo from 'eslint-plugin-bpmn-io';
+import js from '@eslint/js';
import prettierConfig from 'eslint-config-prettier';
import tsParser from '@typescript-eslint/parser';
import globals from 'globals';
-// The bpmn-io recommended config is an array of flat-config objects.
-const recommended = bpmnIo.configs.recommended;
-
export default [
{
ignores: [
@@ -34,9 +31,30 @@ export default [
},
// -----------------------------------------------------------------------
- // 2. Base rules — bpmn-io recommended applied to all remaining files.
+ // 2. Base rules — ESLint recommended plus a few stricter checks, applied
+ // to all remaining files.
// -----------------------------------------------------------------------
- ...recommended,
+ js.configs.recommended,
+ {
+ languageOptions: {
+ ecmaVersion: 2022,
+ globals: globals['shared-node-browser'],
+ },
+ rules: {
+ 'no-bitwise': 'error',
+ 'no-constant-condition': ['error', { checkLoops: true }],
+ 'no-unused-vars': [
+ 'error',
+ {
+ args: 'none',
+ ignoreRestSiblings: true,
+ varsIgnorePattern: '^_',
+ caughtErrors: 'none',
+ },
+ ],
+ 'spaced-comment': ['error', 'always'],
+ },
+ },
// -----------------------------------------------------------------------
// 3. TypeScript source files — add the TS parser and Node globals.
diff --git a/examples/README.md b/examples/README.md
index 98ce191..6d96b4f 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -1,20 +1,19 @@
# Examples
Deployment fixtures for running a compiled `.bpmn` file on Operaton.
-
-One mode exists: `spring-boot/`, with Operaton embedded in a Spring Boot application.
+There is one so far, `spring-boot/`.
## `spring-boot/`
-Operaton 2.1.0 embedded in a Spring Boot 4.0.6 application on Java 17, exposing the Operaton REST API on port 8080.
-It's packaged as a Docker image so the E2E harness can start and stop it.
+Operaton 2.1.0 embedded in a Spring Boot 4.0.6 application on Java 17, serving the Operaton REST API on port 8080.
+It's packaged as a Docker image so the end-to-end tests can start and stop it, and its [README](spring-boot/README.md#running-processes-on-operaton-demo) is a hands-on tour of running the processes in Cockpit and Tasklist.
-The DSL sources under `spring-boot/processes/` cover one construct or construct combination each, and `bpmns build` on any of them produces the deployable `.bpmn`.
+Each source under `spring-boot/processes/` covers one construct or combination, and `bpmns build` on any of them produces a deployable `.bpmn`.
| Source | Covers |
| ----------------------- | -------------------------------------------------------------------------- |
-| `invoice-approval` | `if`/`else` desugaring |
-| `parallel-approval` | `parallel { { } { } }` desugaring |
+| `invoice-approval` | `if`/`else` |
+| `parallel-approval` | `parallel { { } { } }` |
| `service-delegate` | The `delegate` service binding, against a Spring-managed bean |
| `service-expression` | The `expression` service binding, a JUEL expression Operaton evaluates |
| `external-task` | The `topic` binding, against a worker polling `print-label` |
@@ -23,8 +22,8 @@ The DSL sources under `spring-boot/processes/` cover one construct or construct
| `order-handling` | Sub-process containment, plus interrupting and non-interrupting boundaries |
| `order-recovery` | The error and escalation layer, both handler kinds |
| `order-reminder` | The timer and message triggers |
-| `loan-approval` | The `demo` walkthrough |
-| `loan-approval-kopp` | The `demo` walkthrough, parallel-rating variant |
+| `loan-approval` | The demo walkthrough |
+| `loan-approval-kopp` | The demo walkthrough, parallel-rating variant |
| `awaiting-confirmation` | `await message`, released by an outside correlation |
| `charge-with-recovery` | An error boundary on a service task host |
| `compensating-saga` | Compensation raised from a process-level error handler |
@@ -44,19 +43,18 @@ The DSL sources under `spring-boot/processes/` cover one construct or construct
| `nightly-report` | An async join, per-run jobs on a repetition, and a shell task |
| `outage-notice` | A mail task, deployed and never started |
| `expense-claim` | A `while` loop, an `if`/`else`, and a `parallel` block in one process |
+| `claim-routing` | `else fail` closing an `if` chain and a conditioned `parallel` block |
-[Running processes on Operaton](spring-boot/README.md#running-processes-on-operaton-demo) is a hands-on tour of the two loan-approval processes.
-
-### Testcontainers harness
+### End-to-end tests
-The E2E tests in `tests/e2e/` use [testcontainers-node](https://testcontainers.com/) to start the Docker image, deploy compiled BPMN over the Operaton REST API, start instances, and assert what the engine does with what the compiled document only declares.
-The suite builds the image and starts one engine once, and every file runs against it; each file names the example it drives or the examples it deploys.
+The tests in `tests/e2e/` use [testcontainers](https://testcontainers.com/) to start the Docker image, deploy compiled BPMN over the Operaton REST API, start instances, and check what the engine does.
+The suite builds the image and starts one engine, and every test file runs against it.
`deploy-sweep` deploys every golden under `tests/golden/`, every fixture under `tests/fixtures/`, and every example here, once as written and once rebuilt from the tool's own print of it.
-Docker tests run by default, in CI too, and are skipped only when `SKIP_DOCKER_TESTS=true`.
+The Docker tests run by default, in CI too, and are skipped only when `SKIP_DOCKER_TESTS=true`.
-## Adding a new deployment mode
+## Adding a deployment
-1. Create a subdirectory with a `README.md` and whatever runtime files it needs, such as a `pom.xml`, `Dockerfile`, or `docker-compose.yml`.
+1. Create a subdirectory with a `README.md` and the runtime files it needs, such as a `pom.xml`, `Dockerfile`, or `docker-compose.yml`.
2. Implement the `FixtureAdapter` interface from `tests/fixtures/types.ts` in a new file under `tests/fixtures/adapters/`.
-3. Have `startFixture` in `tests/fixtures/index.ts` pick the adapter, for example by a mode argument, since it starts the one adapter today.
+3. Make `startFixture` in `tests/fixtures/index.ts` choose between adapters, for example by a mode argument; it starts the Spring Boot one unconditionally today.
diff --git a/examples/spring-boot/README.md b/examples/spring-boot/README.md
index 3137773..458827b 100644
--- a/examples/spring-boot/README.md
+++ b/examples/spring-boot/README.md
@@ -1,11 +1,9 @@
# examples/spring-boot
-Operaton 2.1.0 embedded in Spring Boot 4.0.6, the deployment fixture for the BPMNscript end-to-end (E2E) test harness.
-The engine starts with nothing pre-deployed; the testcontainers harness deploys definitions at test time over REST.
+Operaton 2.1.0 embedded in Spring Boot 4.0.6, the engine the end-to-end tests deploy to.
+It starts with nothing deployed, and each test deploys its processes over REST.
-It doubles as a hands-on demo.
-The `demo` profile compiles and deploys the example processes and serves the Operaton web apps, Cockpit and Tasklist, so you can start instances and complete tasks by hand.
-See [Running processes on Operaton](#running-processes-on-operaton-demo).
+It's also a hands-on demo: the `demo` profile deploys the compiled example processes and serves the Operaton web apps, Cockpit and Tasklist, so you can start instances and complete tasks by hand ([Running processes on Operaton](#running-processes-on-operaton-demo)).
## Stack
@@ -24,7 +22,7 @@ docker build -t bpmnscript-invoice .
docker run -d --name bpmnscript-invoice -p 8080:8080 bpmnscript-invoice
```
-Wait for the container to become healthy, roughly 30 to 60 seconds on a first run and faster with cached layers, then check the engine is up:
+Wait for the container to become healthy, which takes 30 to 60 seconds, then check the engine is up:
```bash
curl http://localhost:8080/engine-rest/engine
@@ -37,7 +35,7 @@ When you're done:
docker stop bpmnscript-invoice && docker rm bpmnscript-invoice
```
-## REST endpoints the testcontainers harness uses
+## REST endpoints the tests use
The deployment and lifecycle calls the fixture adapter makes:
@@ -49,21 +47,21 @@ The deployment and lifecycle calls the fixture adapter makes:
| `GET` | `/engine-rest/task?processInstanceId={id}` | List active user tasks for a process instance |
| `POST` | `/engine-rest/task/{id}/complete` | Complete a user task, optionally setting variables |
-The assertions reach further into the same API through `tests/helpers/engine-rest.ts`.
+The assertions query more of the same API through `tests/helpers/engine-rest.ts`.
## Admin credentials
Username `demo`, password `demo`, configured in `src/main/resources/application.yml`.
-> For any non-test deployment, replace the `operaton.bpm.admin-user` block with a real credential and probably move it to an env var.
+> For anything beyond local testing, replace the `operaton.bpm.admin-user` block with a real credential, for example from an environment variable.
## Running processes on Operaton (demo)
-Compile any BPMNscript process to BPMN, deploy it to a real Operaton engine, and drive it from Cockpit and Tasklist.
-Loan approval is the worked example, and you can add your own (see [Add your own process](#add-your-own-process)).
+Compile the BPMNscript processes, deploy them to a real Operaton engine, and drive them from Cockpit and Tasklist.
+Loan approval is the worked example, and you can [add your own process](#add-your-own-process).
-The `.bpmnscript` sources live in [`processes/`](processes).
-The compile step turns each one into a deployable `.bpmn` under `src/main/resources/processes/`, which is generated and git-ignored, and the `demo` profile auto-deploys them all on startup.
+The sources are in [`processes/`](processes).
+The compile step writes a `.bpmn` for each into `src/main/resources/processes/`, which is git-ignored, and the `demo` profile deploys them all on startup.
### 1. Build the toolchain
@@ -94,10 +92,10 @@ From `examples/spring-boot/`, either run it with Maven:
mvn clean spring-boot:run -Dspring-boot.run.profiles=demo
```
-The `clean` matters.
-It wipes `target/`, so a process you renamed or removed doesn't linger there as a stale compiled copy; two deployed definitions with the same key make Operaton refuse to start (`The deployment contains definitions with the same key ...`).
+Keep the `clean`.
+It empties `target/`, where a process you renamed or removed would otherwise linger as a stale copy, and two definitions with the same key make Operaton refuse to start (`The deployment contains definitions with the same key ...`).
-Or run it in Docker, noting the `SPRING_PROFILES_ACTIVE=demo` env var:
+Or run it in Docker with `SPRING_PROFILES_ACTIVE=demo`:
```bash
docker build -t bpmnscript-demo .
@@ -107,14 +105,14 @@ docker run -d --name bpmnscript-demo -p 8080:8080 -e SPRING_PROFILES_ACTIVE=demo
### 4. Open the web apps
Go to and log in with `demo` / `demo`.
-Every compiled process is deployed, so pick one in Cockpit to watch instances and live diagrams, or in Tasklist to start one and complete its tasks.
+Every compiled process is deployed: Cockpit shows instances and live diagrams, and Tasklist starts processes and completes their tasks.
### The loan approval walkthrough
-The loan approval example from the [WS-BPEL 2.0 specification](https://docs.oasis-open.org/wsbpel/2.0/wsbpel-v2.0.html).
+This is the loan approval example from the [WS-BPEL 2.0 specification](https://docs.oasis-open.org/wsbpel/2.0/wsbpel-v2.0.html).
A request arrives with an `amount` and a `creditScore`.
Loans under 10,000 are screened by an automated risk assessment, and a low-risk small loan is approved automatically.
-Everything else, meaning large loans and small loans that aren't low-risk, goes to a human "Approve loan" task.
+Everything else, large loans and small loans that aren't low-risk, goes to a human "Approve loan" task.
The outcome is recorded as `decision = ACCEPTED` or `REJECTED`.
Its four service tasks are `JavaDelegate`s in [`src/main/java/com/example/loan/`](src/main/java/com/example/loan).
@@ -142,7 +140,7 @@ Its delegates live in `src/main/java/com/example/loan/kopp/`.
Start it the same way, through Start process and Loan Approval (Kopp 2009), with `amount` and `creditScore` in the start form.
The manual-assessment task's form shows the pre-seeded `assessorRes`: set it to `low` to approve that path, leave it `high` to decline.
-Inputs worth trying:
+Inputs to try:
- `creditScore = 750`, `amount = 5000`: all three rate low.
Both externals rating low already grants acceptance, but the assessor task still appears because the internal rating is low, so complete it to let the instance finish.
@@ -159,7 +157,7 @@ Inputs worth trying:
## Configuration notes
-Classpath auto-deployment is off by default (`operaton.bpm.auto-deployment-enabled: false`).
-The test harness deploys everything over REST, which keeps the fixture stateless between runs.
-The `demo` profile (`application-demo.yml`) turns it on to deploy the compiled processes under `src/main/resources/processes/` at startup.
-H2 runs in-memory, so process state lives only as long as the container, and the two-stage Dockerfile keeps the runtime image down to the fat jar on a plain JRE.
+Classpath auto-deployment is off by default (`operaton.bpm.auto-deployment-enabled: false`), so the tests deploy everything over REST and every run starts from an empty engine.
+The `demo` profile (`application-demo.yml`) turns it on to deploy the compiled processes at startup.
+The history level is `audit`, which records the task and variable history the end-to-end assertions read.
+H2 runs in memory, so process state lives only as long as the container, and the two-stage Dockerfile ships only the fat jar on a plain JRE.
diff --git a/examples/spring-boot/processes/claim-routing.bpmnscript b/examples/spring-boot/processes/claim-routing.bpmnscript
new file mode 100644
index 0000000..9185cf2
--- /dev/null
+++ b/examples/spring-boot/processes/claim-routing.bpmnscript
@@ -0,0 +1,29 @@
+// Every route below runs under a condition and `else fail` adds no fallback,
+// so a claim no condition matches stops with the engine's error instead of
+// slipping past the review. The `if` fails as the claim starts, the
+// `parallel` block when the first review is completed.
+
+process claim-routing(label: "Claim routing") {
+ var amount: number
+ var injury: boolean
+
+ start ClaimReceived(label: "Claim received")
+
+ if (amount <= 1000) {
+ user QuickReview(label: "Review the small claim", assignee: "demo")
+ } else if (amount <= 50000) {
+ user FullReview(label: "Review the claim in full", assignee: "demo")
+ } else fail
+
+ parallel {
+ if (injury) {
+ user MedicalCheck(label: "Check the medical report", assignee: "demo")
+ }
+ if (amount > 500) {
+ user FraudCheck(label: "Check the claim for fraud", assignee: "demo")
+ }
+ else fail
+ }
+
+ end ClaimSettled(label: "Claim settled")
+}
diff --git a/examples/spring-boot/processes/order-intake.bpmnscript b/examples/spring-boot/processes/order-intake.bpmnscript
index db77d7b..c1be2d7 100644
--- a/examples/spring-boot/processes/order-intake.bpmnscript
+++ b/examples/spring-boot/processes/order-intake.bpmnscript
@@ -1,12 +1,9 @@
-// Neither thrown message carries an implementation, so the engine passes the
-// token straight through both.
-
process order-intake {
start OrderReceived message("OrderReceived", label: "An order arrives")
user ConfirmOrder(label: "Confirm the order", assignee: "demo")
- emit message NotifyWarehouse("WarehouseNotified")
+ emit message NotifyWarehouse("WarehouseNotified", class: "com.example.demo.LogDelegate")
- throw message OrderAcknowledged("OrderAcknowledged")
+ throw message OrderAcknowledged("OrderAcknowledged", class: "com.example.demo.LogDelegate")
}
diff --git a/package-lock.json b/package-lock.json
index bcdea8d..62d5d72 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "bpmn-script-workspace",
- "version": "0.0.1",
+ "version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "bpmn-script-workspace",
- "version": "0.0.1",
+ "version": "0.1.0",
"license": "Apache-2.0",
"workspaces": [
"packages/language",
@@ -16,14 +16,14 @@
"tests"
],
"devDependencies": {
- "@types/node": "^26.4.0",
- "@typescript-eslint/parser": "^8.69.0",
- "@vitest/coverage-v8": "^4.1.11",
- "eslint": "^9.0.0",
+ "@eslint/js": "^10.0.1",
+ "@types/node": "^26.6.5",
+ "@typescript-eslint/parser": "^8.71.2",
+ "@vitest/coverage-v8": "^5.0.5",
+ "eslint": "^10.13.0",
"eslint-config-prettier": "^10.1.8",
- "eslint-plugin-bpmn-io": "^2.3.1",
- "prettier": "^3.9.6",
- "shx": "~0.4.0",
+ "globals": "^17.13.0",
+ "prettier": "^3.9.10",
"typescript": "~6.0.0"
},
"engines": {
@@ -288,80 +288,67 @@
"resolved": "packages/transform",
"link": true
},
+ "node_modules/@cacheable/memory": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz",
+ "integrity": "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@cacheable/utils": "^2.5.0",
+ "@keyv/bigmap": "^1.3.1",
+ "hookified": "^1.15.1",
+ "keyv": "^5.6.0"
+ }
+ },
+ "node_modules/@cacheable/utils": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz",
+ "integrity": "sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hashery": "^1.5.1",
+ "keyv": "^5.6.0"
+ }
+ },
"node_modules/@chevrotain/cst-dts-gen": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-12.0.0.tgz",
- "integrity": "sha512-fSL4KXjTl7cDgf0B5Rip9Q05BOrYvkJV/RrBTE/bKDN096E4hN/ySpcBK5B24T76dlQ2i32Zc3PAE27jFnFrKg==",
+ "version": "13.2.0",
+ "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-13.2.0.tgz",
+ "integrity": "sha512-bA9dvWlhAUcHkNwU+8w9yiUxJPlj/Lm3VqS7MD+NbIR/7LmpNLuK/AWNFdCo/T3SK5ND0/UHf3IJvl/Jn/i6yg==",
"license": "Apache-2.0",
"dependencies": {
- "@chevrotain/gast": "12.0.0",
- "@chevrotain/types": "12.0.0"
+ "@chevrotain/gast": "13.2.0",
+ "@chevrotain/types": "13.2.0"
}
},
"node_modules/@chevrotain/gast": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-12.0.0.tgz",
- "integrity": "sha512-1ne/m3XsIT8aEdrvT33so0GUC+wkctpUPK6zU9IlOyJLUbR0rg4G7ZiApiJbggpgPir9ERy3FRjT6T7lpgetnQ==",
+ "version": "13.2.0",
+ "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-13.2.0.tgz",
+ "integrity": "sha512-bCARdAsG+eEbOveSXcOAC7pVxA04I1ionzeMOwIYf5NX7SaS7zgn4Dgug2BSqoL+iyKeMNSorQjsFSHJHsCNwg==",
"license": "Apache-2.0",
"dependencies": {
- "@chevrotain/types": "12.0.0"
+ "@chevrotain/types": "13.2.0"
}
},
"node_modules/@chevrotain/regexp-to-ast": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-12.0.0.tgz",
- "integrity": "sha512-p+EW9MaJwgaHguhoqwOtx/FwuGr+DnNn857sXWOi/mClXIkPGl3rn7hGNWvo31HA3vyeQxjqe+H36yZJwYU8cA==",
+ "version": "13.2.0",
+ "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-13.2.0.tgz",
+ "integrity": "sha512-kxpUkLtiaK09ph+dib+Yvm+3sWSnuwlo25gqfKRgTPNmF6H7uW4gVkMjaRdtnN783S9sM6vUNWh9CsxYX4QwKw==",
"license": "Apache-2.0"
},
"node_modules/@chevrotain/types": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-12.0.0.tgz",
- "integrity": "sha512-S+04vjFQKeuYw0/eW3U52LkAHQsB1ASxsPGsLPUyQgrZ2iNNibQrsidruDzjEX2JYfespXMG0eZmXlhA6z7nWA==",
+ "version": "13.2.0",
+ "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-13.2.0.tgz",
+ "integrity": "sha512-7qrYHRlKfWf2AvBfJi5eVOrKAkbxvMFsy/iIHTGIiApNcEecCaVIdR+mIQhyCBsTDJxBz4JWXHMo6krbhR9hVg==",
"license": "Apache-2.0"
},
"node_modules/@chevrotain/utils": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-12.0.0.tgz",
- "integrity": "sha512-lB59uJoaGIfOOL9knQqQRfhl9g7x8/wqFkp13zTdkRu1huG9kg6IJs1O8hqj9rs6h7orGxHJUKb+mX3rPbWGhA==",
+ "version": "13.2.0",
+ "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-13.2.0.tgz",
+ "integrity": "sha512-SzKYY68rseOrb9KILVzPsl6SjkQtdWw01SRGB5aCVI5kFcHltQsOYV3JB0Ffst72DgkvHCyDQ0NLwxtmCCf97Q==",
"license": "Apache-2.0"
},
- "node_modules/@emnapi/core": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
- "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@emnapi/wasi-threads": "1.2.2",
- "tslib": "^2.4.0"
- }
- },
- "node_modules/@emnapi/runtime": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz",
- "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
- "node_modules/@emnapi/wasi-threads": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
- "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
"node_modules/@esbuild/aix-ppc64": {
"version": "0.28.2",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz",
@@ -847,173 +834,95 @@
}
},
"node_modules/@eslint/config-array": {
- "version": "0.21.2",
- "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz",
- "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==",
+ "version": "0.23.5",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz",
+ "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@eslint/object-schema": "^2.1.7",
+ "@eslint/object-schema": "^3.0.5",
"debug": "^4.3.1",
- "minimatch": "^3.1.5"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
- "node_modules/@eslint/config-array/node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@eslint/config-array/node_modules/brace-expansion": {
- "version": "1.1.21",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
- "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/@eslint/config-array/node_modules/minimatch": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
- "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^1.1.7"
+ "minimatch": "^10.2.4"
},
"engines": {
- "node": "*"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
}
},
"node_modules/@eslint/config-helpers": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz",
- "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==",
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz",
+ "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@eslint/core": "^0.17.0"
+ "@eslint/core": "^1.2.1"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
}
},
"node_modules/@eslint/core": {
- "version": "0.17.0",
- "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz",
- "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz",
+ "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@types/json-schema": "^7.0.15"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- }
- },
- "node_modules/@eslint/eslintrc": {
- "version": "3.3.5",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz",
- "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ajv": "^6.14.0",
- "debug": "^4.3.2",
- "espree": "^10.0.1",
- "globals": "^14.0.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.1",
- "minimatch": "^3.1.5",
- "strip-json-comments": "^3.1.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
- "version": "1.1.21",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
- "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/@eslint/eslintrc/node_modules/minimatch": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
- "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
}
},
"node_modules/@eslint/js": {
- "version": "9.39.4",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz",
- "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==",
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz",
+ "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==",
"dev": true,
"license": "MIT",
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
"url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "eslint": "^10.0.0"
+ },
+ "peerDependenciesMeta": {
+ "eslint": {
+ "optional": true
+ }
}
},
"node_modules/@eslint/object-schema": {
- "version": "2.1.7",
- "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz",
- "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz",
+ "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==",
"dev": true,
"license": "Apache-2.0",
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
}
},
"node_modules/@eslint/plugin-kit": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz",
- "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==",
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.3.tgz",
+ "integrity": "sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@eslint/core": "^0.17.0",
+ "@eslint/core": "^1.2.1",
"levn": "^0.4.1"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
}
},
"node_modules/@grpc/grpc-js": {
- "version": "1.14.4",
- "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.4.tgz",
- "integrity": "sha512-k9Dj3DV/itK9D06Y8f190Qgop7/Ui+D0njFV3LHMPwPT75DpXLQohE9Wmz0QElrJnzsjB7KPWiKJbOl7IPDArQ==",
+ "version": "1.14.6",
+ "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.6.tgz",
+ "integrity": "sha512-SgC/B3/VZ8lTyOZ4Cwk6f1skWhmkNAaVfiX90qd5u1rRXGKk1//8FTUEN9GvOUq7rfWIqAYkA3CoyumYVpOS6g==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -1185,6 +1094,30 @@
"url": "https://opencollective.com/js-sdsl"
}
},
+ "node_modules/@keyv/bigmap": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz",
+ "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hashery": "^1.4.0",
+ "hookified": "^1.15.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "peerDependencies": {
+ "keyv": "^5.6.0"
+ }
+ },
+ "node_modules/@keyv/serialize": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz",
+ "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@kwsites/file-exists": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz",
@@ -1427,69 +1360,13 @@
"node": ">= 10"
}
},
- "node_modules/@napi-rs/wasm-runtime": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz",
- "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "@tybys/wasm-util": "^0.10.3"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/Brooooooklyn"
- },
- "peerDependencies": {
- "@emnapi/core": "^1.7.1",
- "@emnapi/runtime": "^1.7.1"
- }
- },
- "node_modules/@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
"node_modules/@oxc-project/types": {
"version": "0.147.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.147.0.tgz",
"integrity": "sha512-IJ3s6ltHLp45S0bh7phkX+gJO7A1Wuz2EaqpAhb8WjqDwbzMiWKHhyyT42tskaWjEYXtHtVCPpnBJVT9+dcRLg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"funding": {
"url": "https://github.com/sponsors/Boshen"
}
@@ -1584,6 +1461,7 @@
"os": [
"android"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1601,6 +1479,7 @@
"os": [
"android"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1618,6 +1497,7 @@
"os": [
"darwin"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1635,6 +1515,7 @@
"os": [
"darwin"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1652,6 +1533,7 @@
"os": [
"freebsd"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1669,6 +1551,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1686,6 +1569,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1703,6 +1587,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1720,6 +1605,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1737,6 +1623,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1754,6 +1641,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1771,6 +1659,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1788,6 +1677,7 @@
"os": [
"openharmony"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1805,6 +1695,7 @@
"os": [
"win32"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1822,6 +1713,7 @@
"os": [
"win32"
],
+ "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -1831,7 +1723,8 @@
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/@secretlint/core": {
"version": "10.2.2",
@@ -1903,24 +1796,6 @@
"node": ">=20.0.0"
}
},
- "node_modules/@standard-schema/spec": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
- "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@tybys/wasm-util": {
- "version": "0.10.3",
- "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz",
- "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
"node_modules/@types/chai": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
@@ -1962,6 +1837,13 @@
"@types/ssh2": "*"
}
},
+ "node_modules/@types/esrecurse": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz",
+ "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/estree": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
@@ -1977,13 +1859,13 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "26.4.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.0.tgz",
- "integrity": "sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ==",
+ "version": "26.6.5",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.5.tgz",
+ "integrity": "sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "undici-types": "~8.3.0"
+ "undici-types": "~8.9.0"
}
},
"node_modules/@types/ssh2": {
@@ -2023,24 +1905,17 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@types/vscode": {
- "version": "1.134.0",
- "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.134.0.tgz",
- "integrity": "sha512-NDEu0hg4sF7+vvFsADsktqUJ6f80LHSZvVK2Ovo1XiQ0/VHck1O3zst+ZZyVA/uvz6vo6LcuoqU2q48YMqOwWw==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/@typescript-eslint/parser": {
- "version": "8.69.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.69.0.tgz",
- "integrity": "sha512-l4b0DhWioGg6Gt2ebGlvfkFMOjRsauxtsnDRwUSRX1qHq3HdTfQHV8wW9zEXeciai6HfeaKOedQn2Zoofx3WBw==",
+ "version": "8.71.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.71.2.tgz",
+ "integrity": "sha512-aTtmZjp/x3gsGHkDs04/1I8kNogBJkpQaeGaN0PfiG43NzDEmW2n+OP5im9wfsvyX0yP1UZWBrAGtDBfH9jEVw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/scope-manager": "8.69.0",
- "@typescript-eslint/types": "8.69.0",
- "@typescript-eslint/typescript-estree": "8.69.0",
- "@typescript-eslint/visitor-keys": "8.69.0",
+ "@typescript-eslint/scope-manager": "8.71.2",
+ "@typescript-eslint/types": "8.71.2",
+ "@typescript-eslint/typescript-estree": "8.71.2",
+ "@typescript-eslint/visitor-keys": "8.71.2",
"debug": "^4.4.3"
},
"engines": {
@@ -2056,14 +1931,14 @@
}
},
"node_modules/@typescript-eslint/project-service": {
- "version": "8.69.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.69.0.tgz",
- "integrity": "sha512-yi4obFrHMmnsesWehHbkg9zMA7Jt8cXT+mKM08G999pH1yT6nqgsHx7MYm0uY1wAj8CqiBXYRJ7WAT0QdQHQXg==",
+ "version": "8.71.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.2.tgz",
+ "integrity": "sha512-Pd68GsLVh5ZXlcEccFPdhSOvtHZ/2WU0XsA8zmXOS3F158lVlcTLhfQ6qvtL1RzbMie0Kp8xtbVwAg4nejKPHw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.69.0",
- "@typescript-eslint/types": "^8.69.0",
+ "@typescript-eslint/tsconfig-utils": "^8.71.2",
+ "@typescript-eslint/types": "^8.71.2",
"debug": "^4.4.3"
},
"engines": {
@@ -2078,14 +1953,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.69.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.69.0.tgz",
- "integrity": "sha512-ewfspqWvSxKSOaplqAUNbaSFO0eB6w1EtQ+esfYFRm3614Ty4uNtExkcbgd6nWsXphbqKyf9ZYdbZdv2xEoWEQ==",
+ "version": "8.71.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.71.2.tgz",
+ "integrity": "sha512-YF4wgg5iUX5Obywoac27B56FhozMNFhdJSbh11H5GBAwmBtfyRhmgTQqW9tRNNmHDvsZ2CX6UGzoz+YfYn2Leg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.69.0",
- "@typescript-eslint/visitor-keys": "8.69.0"
+ "@typescript-eslint/types": "8.71.2",
+ "@typescript-eslint/visitor-keys": "8.71.2"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2096,9 +1971,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.69.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.69.0.tgz",
- "integrity": "sha512-xNqK7YTDZsLniQMV/4rpFR8Z5JlqeRvVjuG1YgF/mdPVH84HSD19L8CczMA0qg2RfwEV231GHH3VnToJDo4MfQ==",
+ "version": "8.71.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.2.tgz",
+ "integrity": "sha512-jz49TAWokm/7yWD9/o837nYax9DyALxIPOImdImvVzo6canBCZYzin8zJyqNR5k1j9K1DE0bVvr0XYB+99uAdg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2113,9 +1988,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.69.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.69.0.tgz",
- "integrity": "sha512-K3VrubUPhlo9VDBS6QdI8YB5j7ClpqLRdefcz6PFrhnwicehBweqQ9Evhl4l+FYz0HdDmMqIiSX0aldGRYtDCA==",
+ "version": "8.71.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.71.2.tgz",
+ "integrity": "sha512-y5Ukl3oVp7e/VGxqIoEXoeb/Roj71PAJ4WG/N/RGj+eeDvKRLM15kGr9MijLbN0i03S52zxu31Z98E5gWChJKw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2127,16 +2002,16 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.69.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.69.0.tgz",
- "integrity": "sha512-AdFkgqck3Vudb/kWnxlyafU/4aBhHrbQ9locP2N4psXTy5mOBg0SHJumnLvx7r6g1gV4DKvUFwV2nJZBoqOD8w==",
+ "version": "8.71.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.2.tgz",
+ "integrity": "sha512-DgNOEsl4pdYzwSL+N/Cl33tX1Hlw3FvId73LnKXfq7jnrF2viOEn7X+P7RBkkSWCVm92gnWd28GIC5vJuLREeA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/project-service": "8.69.0",
- "@typescript-eslint/tsconfig-utils": "8.69.0",
- "@typescript-eslint/types": "8.69.0",
- "@typescript-eslint/visitor-keys": "8.69.0",
+ "@typescript-eslint/project-service": "8.71.2",
+ "@typescript-eslint/tsconfig-utils": "8.71.2",
+ "@typescript-eslint/types": "8.71.2",
+ "@typescript-eslint/visitor-keys": "8.71.2",
"debug": "^4.4.3",
"minimatch": "^10.2.2",
"semver": "^7.7.3",
@@ -2155,13 +2030,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.69.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.69.0.tgz",
- "integrity": "sha512-+rmdgPA+EXkNgKYvHvFfhrs35utXbwaC5PGpDquSXcoXQDKUA5UjV0LmTucG/4JXkM31BTu4TilHtrN8IVBe8w==",
+ "version": "8.71.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.71.2.tgz",
+ "integrity": "sha512-zozlN0UA32bSG2zkKAgQyRYSbEISVoyU6vvkKYo2aSny74D8Jh4e+POkJ6Lk0dlezZi5x7TtD+88Xb06IB8nhg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.69.0",
+ "@typescript-eslint/types": "8.71.2",
"eslint-visitor-keys": "^5.0.0"
},
"engines": {
@@ -2187,3995 +2062,2078 @@
"node": ">=22.0.0"
}
},
- "node_modules/@unrs/resolver-binding-android-arm-eabi": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz",
- "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==",
- "cpu": [
- "arm"
- ],
+ "node_modules/@vitest/coverage-v8": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-5.0.5.tgz",
+ "integrity": "sha512-4KpkGdIrSqBihx/JyP/e+S+IKB98etg1XDQiLAxksLfcShnwi1VReGeOT9NI43hLHbknosKp/1CCLn9Zgcs8mg==",
"dev": true,
"license": "MIT",
- "optional": true,
- "os": [
- "android"
- ]
+ "dependencies": {
+ "@bcoe/v8-coverage": "^1.0.2",
+ "@vitest/istanbul-lib-coverage": "^1.0.2",
+ "@vitest/istanbul-lib-report": "^1.0.2",
+ "ast-v8-to-istanbul": "^1.0.7",
+ "magicast": "^0.5.5",
+ "obug": "^3.0.0",
+ "std-env": "^4.3.0",
+ "tinyrainbow": "^3.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@vitest/browser": "5.0.5",
+ "vitest": "5.0.5"
+ },
+ "peerDependenciesMeta": {
+ "@vitest/browser": {
+ "optional": true
+ }
+ }
},
- "node_modules/@unrs/resolver-binding-android-arm64": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz",
- "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==",
- "cpu": [
- "arm64"
- ],
+ "node_modules/@vitest/istanbul-lib-coverage": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@vitest/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.2.tgz",
+ "integrity": "sha512-9J/JMwOf9AoJhAywhrn7ScKTL38hsWQP/qPG60OtaAFcQ5OXPwKsxZFlbnuCKmZ61m8/lGgHYnFpdyQZUvG/iA==",
"dev": true,
"license": "MIT",
- "optional": true,
- "os": [
- "android"
- ]
+ "engines": {
+ "node": ">=22"
+ }
},
- "node_modules/@unrs/resolver-binding-darwin-arm64": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz",
- "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==",
- "cpu": [
- "arm64"
- ],
+ "node_modules/@vitest/istanbul-lib-report": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@vitest/istanbul-lib-report/-/istanbul-lib-report-1.0.2.tgz",
+ "integrity": "sha512-gUsfXZJbzPamoIY5TvHFiMMoXESBrUMo+xqaj+rYrWI69+EnvRlYBlP96ZnHPY4vX8kyUpgAnFUCg5wZG/HkDQ==",
"dev": true,
"license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ]
+ "dependencies": {
+ "@vitest/istanbul-lib-coverage": "1.0.2"
+ },
+ "engines": {
+ "node": ">=22"
+ }
},
- "node_modules/@unrs/resolver-binding-darwin-x64": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz",
- "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==",
- "cpu": [
- "x64"
- ],
+ "node_modules/@vitest/mocker": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-5.0.5.tgz",
+ "integrity": "sha512-xLL3lkDegJZw+MGoGaCCsFayDZthGgpAtr3Vziyfc4p7xH89K7KRPcRBBh/kEYm0Aqkt5DtTmkYpBtRV/FrHZg==",
"dev": true,
"license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@unrs/resolver-binding-freebsd-x64": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz",
- "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==",
- "cpu": [
- "x64"
- ],
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.31",
+ "@vitest/spy": "5.0.5",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^1.4.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "msw": "^2.4.9 || ^3.0.0",
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "msw": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vitest/spy": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-5.0.5.tgz",
+ "integrity": "sha512-lwJRExuH417257Q5wv9QYugN9IMJkoxcrKrYxGPQkBzl7wlNpTUxD/5yNX4ESKVUIShKPgkGchYPFMWOOk0wzw==",
"dev": true,
"license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ]
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
},
- "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz",
- "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==",
- "cpu": [
- "arm"
- ],
+ "node_modules/@vscode/vsce": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-4.0.0.tgz",
+ "integrity": "sha512-NImwuLaenMmb5D5Jer9/lzi/F9ZQUBOp8Azhj/BVYcTFgixv8KehFXqEUDjQlD2tAiw2E6dDGyjTuAB//di60A==",
"dev": true,
"license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
+ "dependencies": {
+ "@azure/identity": "^4.13.2",
+ "@napi-rs/keyring": "^1.3.0",
+ "@secretlint/core": "^10.2.2",
+ "@secretlint/secretlint-rule-no-dotenv": "^10.2.2",
+ "@secretlint/secretlint-rule-preset-recommend": "^10.2.2",
+ "@secretlint/source-creator": "^10.2.2",
+ "@secretlint/types": "^10.2.2",
+ "@vscode/vsce-sign": "^2.1.0",
+ "azure-devops-node-api": "^12.5.0",
+ "cockatiel": "^3.2.1",
+ "commander": "^12.1.0",
+ "hosted-git-info": "^4.1.0",
+ "jsonc-parser": "^3.3.1",
+ "marked": "^18.0.11",
+ "mime": "^1.6.0",
+ "minimatch": "^10.2.6",
+ "parse5": "^8.0.1",
+ "proper-lockfile": "^4.1.2",
+ "read": "^1.0.7",
+ "semver": "^7.8.5",
+ "tinyglobby": "^0.2.17",
+ "typed-rest-client": "^1.8.11",
+ "url-join": "^4.0.1",
+ "xml2js": "^0.5.0",
+ "yauzl": "^3.4.0",
+ "yazl": "^2.5.1"
+ },
+ "bin": {
+ "vsce": "vsce"
+ },
+ "engines": {
+ "node": ">= 22"
+ }
},
- "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz",
- "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==",
- "cpu": [
- "arm"
- ],
+ "node_modules/@vscode/vsce-sign": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@vscode/vsce-sign/-/vsce-sign-2.1.0.tgz",
+ "integrity": "sha512-9AQrqazrBgTgRSuwleLVXUrIUphY02/SFCh2TKYoLV/xifJAdblhdmEmw5gUrYSPQ3sRwNs9iyCMD14sATEE6g==",
"dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
+ "hasInstallScript": true,
+ "license": "SEE LICENSE IN LICENSE.txt",
+ "optionalDependencies": {
+ "@vscode/vsce-sign-alpine-arm64": "2.0.6",
+ "@vscode/vsce-sign-alpine-x64": "2.0.6",
+ "@vscode/vsce-sign-darwin-arm64": "2.0.6",
+ "@vscode/vsce-sign-darwin-x64": "2.0.6",
+ "@vscode/vsce-sign-linux-arm": "2.0.6",
+ "@vscode/vsce-sign-linux-arm64": "2.0.6",
+ "@vscode/vsce-sign-linux-x64": "2.0.6",
+ "@vscode/vsce-sign-win32-arm64": "2.0.6",
+ "@vscode/vsce-sign-win32-x64": "2.0.6"
+ }
},
- "node_modules/@unrs/resolver-binding-linux-arm64-gnu": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz",
- "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==",
+ "node_modules/@vscode/vsce-sign-alpine-arm64": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.6.tgz",
+ "integrity": "sha512-wKkJBsvKF+f0GfsUuGT0tSW0kZL87QggEiqNqK6/8hvqsXvpx8OsTEc3mnE1kejkh5r+qUyQ7PtF8jZYN0mo8Q==",
"cpu": [
"arm64"
],
"dev": true,
- "license": "MIT",
+ "license": "SEE LICENSE IN LICENSE.txt",
"optional": true,
"os": [
- "linux"
+ "alpine"
]
},
- "node_modules/@unrs/resolver-binding-linux-arm64-musl": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz",
- "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==",
+ "node_modules/@vscode/vsce-sign-alpine-x64": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.6.tgz",
+ "integrity": "sha512-YoAGlmdK39vKi9jA18i4ufBbd95OqGJxRvF3n6ZbCyziwy3O+JgOpIUPxv5tjeO6gQfx29qBivQ8ZZTUF2Ba0w==",
"cpu": [
- "arm64"
+ "x64"
],
"dev": true,
- "license": "MIT",
+ "license": "SEE LICENSE IN LICENSE.txt",
"optional": true,
"os": [
- "linux"
+ "alpine"
]
},
- "node_modules/@unrs/resolver-binding-linux-loong64-gnu": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz",
- "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==",
+ "node_modules/@vscode/vsce-sign-darwin-arm64": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.6.tgz",
+ "integrity": "sha512-5HMHaJRIQuozm/XQIiJiA0W9uhdblwwl2ZNDSSAeXGO9YhB9MH5C4KIHOmvyjUnKy4UCuiP43VKpIxW1VWP4tQ==",
"cpu": [
- "loong64"
+ "arm64"
],
"dev": true,
- "license": "MIT",
+ "license": "SEE LICENSE IN LICENSE.txt",
"optional": true,
"os": [
- "linux"
+ "darwin"
]
},
- "node_modules/@unrs/resolver-binding-linux-loong64-musl": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz",
- "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==",
+ "node_modules/@vscode/vsce-sign-darwin-x64": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.6.tgz",
+ "integrity": "sha512-25GsUbTAiNfHSuRItoQafXOIpxlYj+IXb4/qarrXu7kmbH94jlm5sdWSCKrrREs8+GsXF1b+l3OB7VJy5jsykw==",
"cpu": [
- "loong64"
+ "x64"
],
"dev": true,
- "license": "MIT",
+ "license": "SEE LICENSE IN LICENSE.txt",
"optional": true,
"os": [
- "linux"
+ "darwin"
]
},
- "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz",
- "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==",
+ "node_modules/@vscode/vsce-sign-linux-arm": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.6.tgz",
+ "integrity": "sha512-UndEc2Xlq4HsuMPnwu7420uqceXjs4yb5W8E2/UkaHBB9OWCwMd3/bRe/1eLe3D8kPpxzcaeTyXiK3RdzS/1CA==",
"cpu": [
- "ppc64"
+ "arm"
],
"dev": true,
- "license": "MIT",
+ "license": "SEE LICENSE IN LICENSE.txt",
"optional": true,
"os": [
"linux"
]
},
- "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz",
- "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==",
+ "node_modules/@vscode/vsce-sign-linux-arm64": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.6.tgz",
+ "integrity": "sha512-cfb1qK7lygtMa4NUl2582nP7aliLYuDEVpAbXJMkDq1qE+olIw/es+C8j1LJwvcRq1I2yWGtSn3EkDp9Dq5FdA==",
"cpu": [
- "riscv64"
+ "arm64"
],
"dev": true,
- "license": "MIT",
+ "license": "SEE LICENSE IN LICENSE.txt",
"optional": true,
"os": [
"linux"
]
},
- "node_modules/@unrs/resolver-binding-linux-riscv64-musl": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz",
- "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==",
+ "node_modules/@vscode/vsce-sign-linux-x64": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.6.tgz",
+ "integrity": "sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA==",
"cpu": [
- "riscv64"
+ "x64"
],
"dev": true,
- "license": "MIT",
+ "license": "SEE LICENSE IN LICENSE.txt",
"optional": true,
"os": [
"linux"
]
},
- "node_modules/@unrs/resolver-binding-linux-s390x-gnu": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz",
- "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==",
+ "node_modules/@vscode/vsce-sign-win32-arm64": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.6.tgz",
+ "integrity": "sha512-ivM/MiGIY0PJNZBoGtlRBM/xDpwbdlCWomUWuLmIxbi1Cxe/1nooYrEQoaHD8ojVRgzdQEUzMsRbyF5cJJgYOg==",
"cpu": [
- "s390x"
+ "arm64"
],
"dev": true,
- "license": "MIT",
+ "license": "SEE LICENSE IN LICENSE.txt",
"optional": true,
"os": [
- "linux"
+ "win32"
]
},
- "node_modules/@unrs/resolver-binding-linux-x64-gnu": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz",
- "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==",
+ "node_modules/@vscode/vsce-sign-win32-x64": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.6.tgz",
+ "integrity": "sha512-mgth9Kvze+u8CruYMmhHw6Zgy3GRX2S+Ed5oSokDEK5vPEwGGKnmuXua9tmFhomeAnhgJnL4DCna3TiNuGrBTQ==",
"cpu": [
"x64"
],
"dev": true,
- "license": "MIT",
+ "license": "SEE LICENSE IN LICENSE.txt",
"optional": true,
"os": [
- "linux"
+ "win32"
]
},
- "node_modules/@unrs/resolver-binding-linux-x64-musl": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz",
- "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==",
- "cpu": [
- "x64"
- ],
+ "node_modules/@vscode/vsce/node_modules/commander": {
+ "version": "12.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
+ "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
"dev": true,
"license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ]
+ "engines": {
+ "node": ">=18"
+ }
},
- "node_modules/@unrs/resolver-binding-openharmony-arm64": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz",
- "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==",
- "cpu": [
- "arm64"
- ],
+ "node_modules/abort-controller": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"dev": true,
"license": "MIT",
- "optional": true,
- "os": [
- "openharmony"
- ]
+ "dependencies": {
+ "event-target-shim": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6.5"
+ }
},
- "node_modules/@unrs/resolver-binding-wasm32-wasi": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz",
- "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==",
- "cpu": [
- "wasm32"
- ],
+ "node_modules/acorn": {
+ "version": "8.19.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.19.0.tgz",
+ "integrity": "sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==",
"dev": true,
"license": "MIT",
- "optional": true,
- "dependencies": {
- "@emnapi/core": "1.10.0",
- "@emnapi/runtime": "1.10.0",
- "@napi-rs/wasm-runtime": "^1.1.4"
+ "bin": {
+ "acorn": "bin/acorn"
},
"engines": {
- "node": ">=14.0.0"
+ "node": ">=0.4.0"
}
},
- "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/core": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
- "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true,
"license": "MIT",
- "optional": true,
- "dependencies": {
- "@emnapi/wasi-threads": "1.2.1",
- "tslib": "^2.4.0"
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
- "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/runtime": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
- "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
+ "node_modules/agent-base": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
+ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
"dev": true,
"license": "MIT",
- "optional": true,
- "dependencies": {
- "tslib": "^2.4.0"
+ "engines": {
+ "node": ">= 14"
}
},
- "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
- "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
+ "node_modules/ajv": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
+ "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
"dev": true,
"license": "MIT",
- "optional": true,
"dependencies": {
- "tslib": "^2.4.0"
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
}
},
- "node_modules/@unrs/resolver-binding-win32-arm64-msvc": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz",
- "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==",
- "cpu": [
- "arm64"
- ],
+ "node_modules/ansi-regex": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
"dev": true,
"license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@unrs/resolver-binding-win32-ia32-msvc": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz",
- "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@unrs/resolver-binding-win32-x64-msvc": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz",
- "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@vitest/coverage-v8": {
- "version": "4.1.11",
- "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.11.tgz",
- "integrity": "sha512-8MVGEFnJIcdGjcbfKmeq8z0pZHH0JlVtoVZH9Q/qwUp6wyFnEJUBMrw9DCaj+ra3vShGmhavjalMIhPNxZAUcw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@bcoe/v8-coverage": "^1.0.2",
- "@vitest/utils": "4.1.11",
- "ast-v8-to-istanbul": "^1.0.0",
- "istanbul-lib-coverage": "^3.2.2",
- "istanbul-lib-report": "^3.0.1",
- "istanbul-reports": "^3.2.0",
- "magicast": "^0.5.2",
- "obug": "^2.1.1",
- "std-env": "^4.0.0-rc.1",
- "tinyrainbow": "^3.1.0"
+ "engines": {
+ "node": ">=12"
},
"funding": {
- "url": "https://opencollective.com/vitest"
- },
- "peerDependencies": {
- "@vitest/browser": "4.1.11",
- "vitest": "4.1.11"
- },
- "peerDependenciesMeta": {
- "@vitest/browser": {
- "optional": true
- }
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
- "node_modules/@vitest/expect": {
- "version": "4.1.11",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz",
- "integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==",
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@standard-schema/spec": "^1.1.0",
- "@types/chai": "^5.2.2",
- "@vitest/spy": "4.1.11",
- "@vitest/utils": "4.1.11",
- "chai": "^6.2.2",
- "tinyrainbow": "^3.1.0"
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
},
"funding": {
- "url": "https://opencollective.com/vitest"
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/@vitest/mocker": {
- "version": "4.1.11",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz",
- "integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==",
+ "node_modules/archiver": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz",
+ "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/spy": "4.1.11",
- "estree-walker": "^3.0.3",
- "magic-string": "^0.30.21"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
- },
- "peerDependencies": {
- "msw": "^2.4.9",
- "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ "archiver-utils": "^5.0.2",
+ "async": "^3.2.4",
+ "buffer-crc32": "^1.0.0",
+ "readable-stream": "^4.0.0",
+ "readdir-glob": "^1.1.2",
+ "tar-stream": "^3.0.0",
+ "zip-stream": "^6.0.1"
},
- "peerDependenciesMeta": {
- "msw": {
- "optional": true
- },
- "vite": {
- "optional": true
- }
+ "engines": {
+ "node": ">= 14"
}
},
- "node_modules/@vitest/pretty-format": {
- "version": "4.1.11",
- "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz",
- "integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==",
+ "node_modules/archiver-utils": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz",
+ "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "tinyrainbow": "^3.1.0"
+ "glob": "^10.0.0",
+ "graceful-fs": "^4.2.0",
+ "is-stream": "^2.0.1",
+ "lazystream": "^1.0.0",
+ "lodash": "^4.17.15",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^4.0.0"
},
- "funding": {
- "url": "https://opencollective.com/vitest"
+ "engines": {
+ "node": ">= 14"
}
},
- "node_modules/@vitest/runner": {
- "version": "4.1.11",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz",
- "integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==",
+ "node_modules/archiver-utils/node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "@vitest/utils": "4.1.11",
- "pathe": "^2.0.3"
+ "engines": {
+ "node": ">=8"
},
"funding": {
- "url": "https://opencollective.com/vitest"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/@vitest/snapshot": {
- "version": "4.1.11",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz",
- "integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==",
+ "node_modules/asn1": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
+ "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "4.1.11",
- "@vitest/utils": "4.1.11",
- "magic-string": "^0.30.21",
- "pathe": "^2.0.3"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
+ "safer-buffer": "~2.1.0"
}
},
- "node_modules/@vitest/spy": {
- "version": "4.1.11",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz",
- "integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==",
+ "node_modules/assertion-error": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+ "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
"dev": true,
"license": "MIT",
- "funding": {
- "url": "https://opencollective.com/vitest"
+ "engines": {
+ "node": ">=12"
}
},
- "node_modules/@vitest/utils": {
- "version": "4.1.11",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz",
- "integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==",
+ "node_modules/ast-v8-to-istanbul": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.7.tgz",
+ "integrity": "sha512-kFL68AG6ajd8fg248zwM9GQrUWEp79gsmjum34OEXjs4yHuUMZfYKwOLW9GMmB4oNvVrj+EAGxsP7ye2UR9UlA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "4.1.11",
- "convert-source-map": "^2.0.0",
- "tinyrainbow": "^3.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/vitest"
+ "@jridgewell/trace-mapping": "^0.3.31",
+ "estree-walker": "^3.0.3",
+ "js-tokens": "^10.0.0"
}
},
- "node_modules/@vscode/vsce": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-4.0.0.tgz",
- "integrity": "sha512-NImwuLaenMmb5D5Jer9/lzi/F9ZQUBOp8Azhj/BVYcTFgixv8KehFXqEUDjQlD2tAiw2E6dDGyjTuAB//di60A==",
+ "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz",
+ "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/async": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/async-lock": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz",
+ "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/azure-devops-node-api": {
+ "version": "12.5.0",
+ "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz",
+ "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@azure/identity": "^4.13.2",
- "@napi-rs/keyring": "^1.3.0",
- "@secretlint/core": "^10.2.2",
- "@secretlint/secretlint-rule-no-dotenv": "^10.2.2",
- "@secretlint/secretlint-rule-preset-recommend": "^10.2.2",
- "@secretlint/source-creator": "^10.2.2",
- "@secretlint/types": "^10.2.2",
- "@vscode/vsce-sign": "^2.1.0",
- "azure-devops-node-api": "^12.5.0",
- "cockatiel": "^3.2.1",
- "commander": "^12.1.0",
- "hosted-git-info": "^4.1.0",
- "jsonc-parser": "^3.3.1",
- "marked": "^18.0.11",
- "mime": "^1.6.0",
- "minimatch": "^10.2.6",
- "parse5": "^8.0.1",
- "proper-lockfile": "^4.1.2",
- "read": "^1.0.7",
- "semver": "^7.8.5",
- "tinyglobby": "^0.2.17",
- "typed-rest-client": "^1.8.11",
- "url-join": "^4.0.1",
- "xml2js": "^0.5.0",
- "yauzl": "^3.4.0",
- "yazl": "^2.5.1"
- },
- "bin": {
- "vsce": "vsce"
+ "tunnel": "0.0.6",
+ "typed-rest-client": "^1.8.4"
+ }
+ },
+ "node_modules/b4a": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz",
+ "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "react-native-b4a": "*"
},
+ "peerDependenciesMeta": {
+ "react-native-b4a": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "license": "MIT",
"engines": {
- "node": ">= 22"
+ "node": "18 || 20 || >=22"
}
},
- "node_modules/@vscode/vsce-sign": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@vscode/vsce-sign/-/vsce-sign-2.1.0.tgz",
- "integrity": "sha512-9AQrqazrBgTgRSuwleLVXUrIUphY02/SFCh2TKYoLV/xifJAdblhdmEmw5gUrYSPQ3sRwNs9iyCMD14sATEE6g==",
+ "node_modules/bare-events": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.1.tgz",
+ "integrity": "sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg==",
"dev": true,
- "hasInstallScript": true,
- "license": "SEE LICENSE IN LICENSE.txt",
- "optionalDependencies": {
- "@vscode/vsce-sign-alpine-arm64": "2.0.6",
- "@vscode/vsce-sign-alpine-x64": "2.0.6",
- "@vscode/vsce-sign-darwin-arm64": "2.0.6",
- "@vscode/vsce-sign-darwin-x64": "2.0.6",
- "@vscode/vsce-sign-linux-arm": "2.0.6",
- "@vscode/vsce-sign-linux-arm64": "2.0.6",
- "@vscode/vsce-sign-linux-x64": "2.0.6",
- "@vscode/vsce-sign-win32-arm64": "2.0.6",
- "@vscode/vsce-sign-win32-x64": "2.0.6"
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "bare-abort-controller": "*"
+ },
+ "peerDependenciesMeta": {
+ "bare-abort-controller": {
+ "optional": true
+ }
}
},
- "node_modules/@vscode/vsce-sign-alpine-arm64": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.6.tgz",
- "integrity": "sha512-wKkJBsvKF+f0GfsUuGT0tSW0kZL87QggEiqNqK6/8hvqsXvpx8OsTEc3mnE1kejkh5r+qUyQ7PtF8jZYN0mo8Q==",
- "cpu": [
- "arm64"
- ],
+ "node_modules/bare-fs": {
+ "version": "4.7.2",
+ "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.2.tgz",
+ "integrity": "sha512-aTvMFUWkBmjzKtEQMDGGDNF8bkfpD5N1b/FCwt7A3wrU4t1o/e/85Wzkluh6JlODCjqVESYCkQCdTXqZ9G7VFg==",
"dev": true,
- "license": "SEE LICENSE IN LICENSE.txt",
- "optional": true,
- "os": [
- "alpine"
- ]
- },
- "node_modules/@vscode/vsce-sign-alpine-x64": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.6.tgz",
- "integrity": "sha512-YoAGlmdK39vKi9jA18i4ufBbd95OqGJxRvF3n6ZbCyziwy3O+JgOpIUPxv5tjeO6gQfx29qBivQ8ZZTUF2Ba0w==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "SEE LICENSE IN LICENSE.txt",
- "optional": true,
- "os": [
- "alpine"
- ]
- },
- "node_modules/@vscode/vsce-sign-darwin-arm64": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.6.tgz",
- "integrity": "sha512-5HMHaJRIQuozm/XQIiJiA0W9uhdblwwl2ZNDSSAeXGO9YhB9MH5C4KIHOmvyjUnKy4UCuiP43VKpIxW1VWP4tQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "SEE LICENSE IN LICENSE.txt",
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@vscode/vsce-sign-darwin-x64": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.6.tgz",
- "integrity": "sha512-25GsUbTAiNfHSuRItoQafXOIpxlYj+IXb4/qarrXu7kmbH94jlm5sdWSCKrrREs8+GsXF1b+l3OB7VJy5jsykw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "SEE LICENSE IN LICENSE.txt",
- "optional": true,
- "os": [
- "darwin"
- ]
- },
- "node_modules/@vscode/vsce-sign-linux-arm": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.6.tgz",
- "integrity": "sha512-UndEc2Xlq4HsuMPnwu7420uqceXjs4yb5W8E2/UkaHBB9OWCwMd3/bRe/1eLe3D8kPpxzcaeTyXiK3RdzS/1CA==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "SEE LICENSE IN LICENSE.txt",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@vscode/vsce-sign-linux-arm64": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.6.tgz",
- "integrity": "sha512-cfb1qK7lygtMa4NUl2582nP7aliLYuDEVpAbXJMkDq1qE+olIw/es+C8j1LJwvcRq1I2yWGtSn3EkDp9Dq5FdA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "SEE LICENSE IN LICENSE.txt",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@vscode/vsce-sign-linux-x64": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.6.tgz",
- "integrity": "sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "SEE LICENSE IN LICENSE.txt",
- "optional": true,
- "os": [
- "linux"
- ]
- },
- "node_modules/@vscode/vsce-sign-win32-arm64": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.6.tgz",
- "integrity": "sha512-ivM/MiGIY0PJNZBoGtlRBM/xDpwbdlCWomUWuLmIxbi1Cxe/1nooYrEQoaHD8ojVRgzdQEUzMsRbyF5cJJgYOg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "SEE LICENSE IN LICENSE.txt",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@vscode/vsce-sign-win32-x64": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.6.tgz",
- "integrity": "sha512-mgth9Kvze+u8CruYMmhHw6Zgy3GRX2S+Ed5oSokDEK5vPEwGGKnmuXua9tmFhomeAnhgJnL4DCna3TiNuGrBTQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "SEE LICENSE IN LICENSE.txt",
- "optional": true,
- "os": [
- "win32"
- ]
- },
- "node_modules/@vscode/vsce/node_modules/commander": {
- "version": "12.1.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
- "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/abort-controller": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
- "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "event-target-shim": "^5.0.0"
- },
- "engines": {
- "node": ">=6.5"
- }
- },
- "node_modules/acorn": {
- "version": "8.16.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
- "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
- "dev": true,
- "license": "MIT",
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true,
- "license": "MIT",
- "peerDependencies": {
- "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/agent-base": {
- "version": "7.1.4",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
- "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/ajv": {
- "version": "6.15.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
- "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/ansi-regex": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
- "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
- }
- },
- "node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/archiver": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz",
- "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "archiver-utils": "^5.0.2",
- "async": "^3.2.4",
- "buffer-crc32": "^1.0.0",
- "readable-stream": "^4.0.0",
- "readdir-glob": "^1.1.2",
- "tar-stream": "^3.0.0",
- "zip-stream": "^6.0.1"
- },
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/archiver-utils": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz",
- "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "glob": "^10.0.0",
- "graceful-fs": "^4.2.0",
- "is-stream": "^2.0.1",
- "lazystream": "^1.0.0",
- "lodash": "^4.17.15",
- "normalize-path": "^3.0.0",
- "readable-stream": "^4.0.0"
- },
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/archiver-utils/node_modules/is-stream": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
- "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true,
- "license": "Python-2.0"
- },
- "node_modules/array-buffer-byte-length": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
- "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "is-array-buffer": "^3.0.5"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array-includes": {
- "version": "3.1.9",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
- "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.4",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.24.0",
- "es-object-atoms": "^1.1.1",
- "get-intrinsic": "^1.3.0",
- "is-string": "^1.1.1",
- "math-intrinsics": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.findlast": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
- "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
- "es-shim-unscopables": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.flat": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
- "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.5",
- "es-shim-unscopables": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.flatmap": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
- "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.5",
- "es-shim-unscopables": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.tosorted": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz",
- "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.3",
- "es-errors": "^1.3.0",
- "es-shim-unscopables": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/arraybuffer.prototype.slice": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
- "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "array-buffer-byte-length": "^1.0.1",
- "call-bind": "^1.0.8",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.5",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.6",
- "is-array-buffer": "^3.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/asn1": {
- "version": "0.2.6",
- "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
- "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "safer-buffer": "~2.1.0"
- }
- },
- "node_modules/assertion-error": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
- "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/ast-v8-to-istanbul": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.7.tgz",
- "integrity": "sha512-kFL68AG6ajd8fg248zwM9GQrUWEp79gsmjum34OEXjs4yHuUMZfYKwOLW9GMmB4oNvVrj+EAGxsP7ye2UR9UlA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jridgewell/trace-mapping": "^0.3.31",
- "estree-walker": "^3.0.3",
- "js-tokens": "^10.0.0"
- }
- },
- "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz",
- "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/async": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
- "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/async-function": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
- "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/async-lock": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz",
- "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/available-typed-arrays": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
- "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "possible-typed-array-names": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/azure-devops-node-api": {
- "version": "12.5.0",
- "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz",
- "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "tunnel": "0.0.6",
- "typed-rest-client": "^1.8.4"
- }
- },
- "node_modules/b4a": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz",
- "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==",
- "dev": true,
- "license": "Apache-2.0",
- "peerDependencies": {
- "react-native-b4a": "*"
- },
- "peerDependenciesMeta": {
- "react-native-b4a": {
- "optional": true
- }
- }
- },
- "node_modules/balanced-match": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
- "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
- "license": "MIT",
- "engines": {
- "node": "18 || 20 || >=22"
- }
- },
- "node_modules/bare-events": {
- "version": "2.9.1",
- "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.1.tgz",
- "integrity": "sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg==",
- "dev": true,
- "license": "Apache-2.0",
- "peerDependencies": {
- "bare-abort-controller": "*"
- },
- "peerDependenciesMeta": {
- "bare-abort-controller": {
- "optional": true
- }
- }
- },
- "node_modules/bare-fs": {
- "version": "4.7.2",
- "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.2.tgz",
- "integrity": "sha512-aTvMFUWkBmjzKtEQMDGGDNF8bkfpD5N1b/FCwt7A3wrU4t1o/e/85Wzkluh6JlODCjqVESYCkQCdTXqZ9G7VFg==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "bare-events": "^2.5.4",
- "bare-path": "^3.0.0",
- "bare-stream": "^2.6.4",
- "bare-url": "^2.2.2",
- "fast-fifo": "^1.3.2"
- },
- "engines": {
- "bare": ">=1.16.0"
- },
- "peerDependencies": {
- "bare-buffer": "*"
- },
- "peerDependenciesMeta": {
- "bare-buffer": {
- "optional": true
- }
- }
- },
- "node_modules/bare-os": {
- "version": "3.9.1",
- "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.1.tgz",
- "integrity": "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "bare": ">=1.14.0"
- }
- },
- "node_modules/bare-path": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.1.tgz",
- "integrity": "sha512-ghj2DSK/2e99a1anTVPCV4m4YIYtrbXhfM7V3D7XZLOTsybnYyaJloymGqssQc8l/or0UoDyRtNQkmkEF/ysgQ==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "bare-os": "^3.0.1"
- }
- },
- "node_modules/bare-stream": {
- "version": "2.13.3",
- "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.3.tgz",
- "integrity": "sha512-Kc+brLqvEqGkjyfiwJmImAOqLZL7OsoLKuavx+hJjgVV3nLTOjloJyPMFxjUPerGGHrNH0fLU06jjykMLWrERQ==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "b4a": "^1.8.1",
- "streamx": "^2.25.0",
- "teex": "^1.0.1"
- },
- "peerDependencies": {
- "bare-abort-controller": "*",
- "bare-buffer": "*",
- "bare-events": "*"
- },
- "peerDependenciesMeta": {
- "bare-abort-controller": {
- "optional": true
- },
- "bare-buffer": {
- "optional": true
- },
- "bare-events": {
- "optional": true
- }
- }
- },
- "node_modules/bare-url": {
- "version": "2.4.5",
- "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.5.tgz",
- "integrity": "sha512-K+y9xF1tN+CdPu4qWwr0QiK1Al07eFPGYK5M2pDXcmHdMdgC/tT/bpmMe1hrmRHaidKLkXrC+cRNYf3XVDUhSQ==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "bare-path": "^3.0.0"
- }
- },
- "node_modules/base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT"
- },
- "node_modules/bcrypt-pbkdf": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
- "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "tweetnacl": "^0.14.3"
- }
- },
- "node_modules/binaryextensions": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz",
- "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==",
- "dev": true,
- "license": "Artistic-2.0",
- "dependencies": {
- "editions": "^6.21.0"
- },
- "engines": {
- "node": ">=4"
- },
- "funding": {
- "url": "https://bevry.me/fund"
- }
- },
- "node_modules/bl": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
- "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "buffer": "^5.5.0",
- "inherits": "^2.0.4",
- "readable-stream": "^3.4.0"
- }
- },
- "node_modules/bl/node_modules/buffer": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
- "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.1.13"
- }
- },
- "node_modules/bl/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/boundary": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz",
- "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==",
- "dev": true,
- "license": "BSD-2-Clause"
- },
- "node_modules/bpmn-auto-layout": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/bpmn-auto-layout/-/bpmn-auto-layout-1.3.0.tgz",
- "integrity": "sha512-ufjMy1MaaZxkQF7f2wY6EL6TnRMSFr/r9eBhp0QvS41UHXW77aQVt65+dn2MmVMlHdyvZyOMNYXO2qYpgX6bQA==",
- "license": "MIT",
- "workspaces": [
- "example"
- ],
- "dependencies": {
- "bpmn-moddle": "^10.0.0",
- "min-dash": "^5.0.0"
- },
- "engines": {
- "node": ">= 18"
- }
- },
- "node_modules/bpmn-moddle": {
- "version": "10.2.0",
- "resolved": "https://registry.npmjs.org/bpmn-moddle/-/bpmn-moddle-10.2.0.tgz",
- "integrity": "sha512-rjPr+hvh43DH9BXUHnXHVNcILYJbZ4rJdYY0GRV7ve99MURNjpIp/mCL8UJSz923uXJ4Doa/bEgBEsG01fPoYQ==",
- "license": "MIT",
- "dependencies": {
- "min-dash": "^5.1.0",
- "moddle": "^8.2.1",
- "moddle-xml": "^12.2.0"
- },
- "engines": {
- "node": ">= 20.12"
- }
- },
- "node_modules/brace-expansion": {
- "version": "5.0.9",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
- "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^4.0.2"
- },
- "engines": {
- "node": "20 || >=22"
- }
- },
- "node_modules/braces": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
- "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "fill-range": "^7.1.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/buffer": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
- "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.2.1"
- }
- },
- "node_modules/buffer-crc32": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz",
- "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/buffer-equal-constant-time": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
- "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
- "dev": true,
- "license": "BSD-3-Clause"
- },
- "node_modules/buildcheck": {
- "version": "0.0.7",
- "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.7.tgz",
- "integrity": "sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==",
- "dev": true,
- "optional": true,
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/bundle-name": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
- "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "run-applescript": "^7.0.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/byline": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz",
- "integrity": "sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/call-bind": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz",
- "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.2",
- "es-define-property": "^1.0.1",
- "get-intrinsic": "^1.3.0",
- "set-function-length": "^1.2.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/call-bind-apply-helpers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
- "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/call-bound": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
- "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.2",
- "get-intrinsic": "^1.3.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/chai": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
- "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/chevrotain": {
- "version": "12.0.0",
- "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-12.0.0.tgz",
- "integrity": "sha512-csJvb+6kEiQaqo1woTdSAuOWdN0WTLIydkKrBnS+V5gZz0oqBrp4kQ35519QgK6TpBThiG3V1vNSHlIkv4AglQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@chevrotain/cst-dts-gen": "12.0.0",
- "@chevrotain/gast": "12.0.0",
- "@chevrotain/regexp-to-ast": "12.0.0",
- "@chevrotain/types": "12.0.0",
- "@chevrotain/utils": "12.0.0"
- },
- "engines": {
- "node": ">=22.0.0"
- }
- },
- "node_modules/chevrotain-allstar": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.4.3.tgz",
- "integrity": "sha512-2X4mkroolSMKqW+H22pyPMUVDqYZzPhephTmg/NODKb1IGYPHfxfhcW0EjS7wcPJNbze2i4vBWT7zT5FKF2lrQ==",
- "license": "MIT",
- "dependencies": {
- "lodash-es": "^4.18.1"
- },
- "peerDependencies": {
- "chevrotain": "^12.0.0"
- }
- },
- "node_modules/chownr": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
- "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/cliui": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
- "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "wrap-ansi": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/cliui/node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/cliui/node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/cliui/node_modules/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/cliui/node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/cliui/node_modules/wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/cockatiel": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz",
- "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/commander": {
- "version": "15.0.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz",
- "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==",
- "license": "MIT",
- "engines": {
- "node": ">=22.12.0"
- }
- },
- "node_modules/comment-parser": {
- "version": "1.4.7",
- "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.7.tgz",
- "integrity": "sha512-0h+uSNtQGW3D98eQt3jJ8L06Fves8hncB4V/PKdw/Qb8Hnk19VaKuTr55UNRYiSoVa7WwrFls+rh3ux9agmkeQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 12.0.0"
- }
- },
- "node_modules/compress-commons": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz",
- "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "crc-32": "^1.2.0",
- "crc32-stream": "^6.0.0",
- "is-stream": "^2.0.1",
- "normalize-path": "^3.0.0",
- "readable-stream": "^4.0.0"
- },
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/compress-commons/node_modules/is-stream": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
- "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/concurrently": {
- "version": "10.0.5",
- "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-10.0.5.tgz",
- "integrity": "sha512-JaP/CoftUrCcAFW/g//RbgEGwlelnEae6cfBLgH6ZdO6s8jPkn6p9SB9u6pdVxYXoiSnFqseOlHfrEfF82TVOg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "chalk": "5.6.2",
- "rxjs": "7.8.2",
- "shell-quote": "1.9.0",
- "supports-color": "10.2.2",
- "tree-kill": "1.2.2",
- "yargs": "18.0.0"
- },
- "bin": {
- "conc": "dist/bin/index.js",
- "concurrently": "dist/bin/index.js"
- },
- "engines": {
- "node": ">=22"
- },
- "funding": {
- "url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
- }
- },
- "node_modules/concurrently/node_modules/ansi-styles": {
- "version": "6.2.3",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
- "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/concurrently/node_modules/chalk": {
- "version": "5.6.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
- "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^12.17.0 || ^14.13 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/concurrently/node_modules/cliui": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
- "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "string-width": "^7.2.0",
- "strip-ansi": "^7.1.0",
- "wrap-ansi": "^9.0.0"
- },
- "engines": {
- "node": ">=20"
- }
- },
- "node_modules/concurrently/node_modules/emoji-regex": {
- "version": "10.6.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
- "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/concurrently/node_modules/string-width": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
- "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^10.3.0",
- "get-east-asian-width": "^1.0.0",
- "strip-ansi": "^7.1.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/concurrently/node_modules/supports-color": {
- "version": "10.2.2",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz",
- "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/chalk/supports-color?sponsor=1"
- }
- },
- "node_modules/concurrently/node_modules/wrap-ansi": {
- "version": "9.0.2",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
- "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^6.2.1",
- "string-width": "^7.0.0",
- "strip-ansi": "^7.1.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/concurrently/node_modules/yargs": {
- "version": "18.0.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz",
- "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cliui": "^9.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "string-width": "^7.2.0",
- "y18n": "^5.0.5",
- "yargs-parser": "^22.0.0"
- },
- "engines": {
- "node": "^20.19.0 || ^22.12.0 || >=23"
- }
- },
- "node_modules/concurrently/node_modules/yargs-parser": {
- "version": "22.0.0",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz",
- "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": "^20.19.0 || ^22.12.0 || >=23"
- }
- },
- "node_modules/convert-source-map": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
- "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/core-util-is": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
- "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/cpu-features": {
- "version": "0.0.10",
- "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz",
- "integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==",
- "dev": true,
- "hasInstallScript": true,
- "optional": true,
- "dependencies": {
- "buildcheck": "~0.0.6",
- "nan": "^2.19.0"
- },
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/crc-32": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
- "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
- "dev": true,
- "license": "Apache-2.0",
- "bin": {
- "crc32": "bin/crc32.njs"
- },
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/crc32-stream": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz",
- "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "crc-32": "^1.2.0",
- "readable-stream": "^4.0.0"
- },
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/cross-spawn": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
- "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/data-view-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
- "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/data-view-byte-length": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
- "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/inspect-js"
- }
- },
- "node_modules/data-view-byte-offset": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
- "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "es-errors": "^1.3.0",
- "is-data-view": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/debug": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
- "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ms": "^2.1.3"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/default-browser": {
- "version": "5.5.1",
- "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz",
- "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "bundle-name": "^4.1.0",
- "default-browser-id": "^5.0.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/default-browser-id": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz",
- "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/define-data-property": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
- "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-define-property": "^1.0.0",
- "es-errors": "^1.3.0",
- "gopd": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/define-lazy-prop": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
- "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/define-properties": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
- "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "define-data-property": "^1.0.1",
- "has-property-descriptors": "^1.0.0",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/detect-libc": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
- "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/docker-compose": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-1.4.2.tgz",
- "integrity": "sha512-rPHigTKGaEHpkUmfd69QgaOp+Os5vGJwG/Ry8lcr8W/382AmI+z/D7qoa9BybKIkqNppaIbs8RYeHSevdQjWww==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "yaml": "^2.2.2"
- },
- "engines": {
- "node": ">= 6.0.0"
- }
- },
- "node_modules/docker-modem": {
- "version": "5.0.7",
- "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-5.0.7.tgz",
- "integrity": "sha512-XJgGhoR/CLpqshm4d3L7rzH6t8NgDFUIIpztYlLHIApeJjMZKYJMz2zxPsYxnejq5h3ELYSw/RBsi3t5h7gNTA==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "debug": "^4.1.1",
- "readable-stream": "^3.5.0",
- "split-ca": "^1.0.1",
- "ssh2": "^1.15.0"
- },
- "engines": {
- "node": ">= 8.0"
- }
- },
- "node_modules/docker-modem/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/dockerode": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-5.0.1.tgz",
- "integrity": "sha512-avsq/xk4YPIrn0CgleX5bjT9Y8IT1p9PxrNQ++RBQ2WEyFfHCTDsT9kmyxz+H/axnjAwg8wJWEIuPGOUuNupiA==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@balena/dockerignore": "^1.0.2",
- "@grpc/grpc-js": "^1.11.1",
- "@grpc/proto-loader": "^0.7.13",
- "docker-modem": "^5.0.7",
- "protobufjs": "^7.3.2",
- "tar-fs": "^2.1.4"
- },
- "engines": {
- "node": ">= 14.17"
- }
- },
- "node_modules/dockerode/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/dockerode/node_modules/tar-fs": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.5.tgz",
- "integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "chownr": "^1.1.1",
- "mkdirp-classic": "^0.5.2",
- "pump": "^3.0.0",
- "tar-stream": "^2.1.4"
- }
- },
- "node_modules/dockerode/node_modules/tar-stream": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
- "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "bl": "^4.0.3",
- "end-of-stream": "^1.4.1",
- "fs-constants": "^1.0.0",
- "inherits": "^2.0.3",
- "readable-stream": "^3.1.1"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/dunder-proto": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
- "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind-apply-helpers": "^1.0.1",
- "es-errors": "^1.3.0",
- "gopd": "^1.2.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/eastasianwidth": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
- "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/ecdsa-sig-formatter": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
- "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "safe-buffer": "^5.0.1"
- }
- },
- "node_modules/editions": {
- "version": "6.22.0",
- "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz",
- "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==",
- "dev": true,
- "license": "Artistic-2.0",
- "dependencies": {
- "version-range": "^4.15.0"
- },
- "engines": {
- "ecmascript": ">= es5",
- "node": ">=4"
- },
- "funding": {
- "url": "https://bevry.me/fund"
- }
- },
- "node_modules/emoji-regex": {
- "version": "9.2.2",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
- "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/end-of-stream": {
- "version": "1.4.5",
- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
- "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "once": "^1.4.0"
- }
- },
- "node_modules/entities": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz",
- "integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==",
- "dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=20.19.0"
- },
- "funding": {
- "url": "https://github.com/fb55/entities?sponsor=1"
- }
- },
- "node_modules/es-abstract": {
- "version": "1.24.2",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz",
- "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "array-buffer-byte-length": "^1.0.2",
- "arraybuffer.prototype.slice": "^1.0.4",
- "available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.4",
- "data-view-buffer": "^1.0.2",
- "data-view-byte-length": "^1.0.2",
- "data-view-byte-offset": "^1.0.1",
- "es-define-property": "^1.0.1",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.1.1",
- "es-set-tostringtag": "^2.1.0",
- "es-to-primitive": "^1.3.0",
- "function.prototype.name": "^1.1.8",
- "get-intrinsic": "^1.3.0",
- "get-proto": "^1.0.1",
- "get-symbol-description": "^1.1.0",
- "globalthis": "^1.0.4",
- "gopd": "^1.2.0",
- "has-property-descriptors": "^1.0.2",
- "has-proto": "^1.2.0",
- "has-symbols": "^1.1.0",
- "hasown": "^2.0.2",
- "internal-slot": "^1.1.0",
- "is-array-buffer": "^3.0.5",
- "is-callable": "^1.2.7",
- "is-data-view": "^1.0.2",
- "is-negative-zero": "^2.0.3",
- "is-regex": "^1.2.1",
- "is-set": "^2.0.3",
- "is-shared-array-buffer": "^1.0.4",
- "is-string": "^1.1.1",
- "is-typed-array": "^1.1.15",
- "is-weakref": "^1.1.1",
- "math-intrinsics": "^1.1.0",
- "object-inspect": "^1.13.4",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.7",
- "own-keys": "^1.0.1",
- "regexp.prototype.flags": "^1.5.4",
- "safe-array-concat": "^1.1.3",
- "safe-push-apply": "^1.0.0",
- "safe-regex-test": "^1.1.0",
- "set-proto": "^1.0.0",
- "stop-iteration-iterator": "^1.1.0",
- "string.prototype.trim": "^1.2.10",
- "string.prototype.trimend": "^1.0.9",
- "string.prototype.trimstart": "^1.0.8",
- "typed-array-buffer": "^1.0.3",
- "typed-array-byte-length": "^1.0.3",
- "typed-array-byte-offset": "^1.0.4",
- "typed-array-length": "^1.0.7",
- "unbox-primitive": "^1.1.0",
- "which-typed-array": "^1.1.19"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/es-define-property": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
- "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-errors": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
- "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-iterator-helpers": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.2.tgz",
- "integrity": "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==",
- "dev": true,
- "license": "MIT",
+ "license": "Apache-2.0",
"dependencies": {
- "call-bind": "^1.0.9",
- "call-bound": "^1.0.4",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.24.2",
- "es-errors": "^1.3.0",
- "es-set-tostringtag": "^2.1.0",
- "function-bind": "^1.1.2",
- "get-intrinsic": "^1.3.0",
- "globalthis": "^1.0.4",
- "gopd": "^1.2.0",
- "has-property-descriptors": "^1.0.2",
- "has-proto": "^1.2.0",
- "has-symbols": "^1.1.0",
- "internal-slot": "^1.1.0",
- "iterator.prototype": "^1.1.5",
- "math-intrinsics": "^1.1.0"
+ "bare-events": "^2.5.4",
+ "bare-path": "^3.0.0",
+ "bare-stream": "^2.6.4",
+ "bare-url": "^2.2.2",
+ "fast-fifo": "^1.3.2"
},
"engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-module-lexer": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz",
- "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/es-object-atoms": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
- "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0"
+ "bare": ">=1.16.0"
},
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-set-tostringtag": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
- "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.6",
- "has-tostringtag": "^1.0.2",
- "hasown": "^2.0.2"
+ "peerDependencies": {
+ "bare-buffer": "*"
},
- "engines": {
- "node": ">= 0.4"
+ "peerDependenciesMeta": {
+ "bare-buffer": {
+ "optional": true
+ }
}
},
- "node_modules/es-shim-unscopables": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
- "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
+ "node_modules/bare-os": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.1.tgz",
+ "integrity": "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "hasown": "^2.0.2"
- },
+ "license": "Apache-2.0",
"engines": {
- "node": ">= 0.4"
+ "bare": ">=1.14.0"
}
},
- "node_modules/es-to-primitive": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
- "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
+ "node_modules/bare-path": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.1.tgz",
+ "integrity": "sha512-ghj2DSK/2e99a1anTVPCV4m4YIYtrbXhfM7V3D7XZLOTsybnYyaJloymGqssQc8l/or0UoDyRtNQkmkEF/ysgQ==",
"dev": true,
- "license": "MIT",
+ "license": "Apache-2.0",
"dependencies": {
- "is-callable": "^1.2.7",
- "is-date-object": "^1.0.5",
- "is-symbol": "^1.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "bare-os": "^3.0.1"
}
},
- "node_modules/esbuild": {
- "version": "0.28.2",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
- "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==",
+ "node_modules/bare-stream": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.3.tgz",
+ "integrity": "sha512-Kc+brLqvEqGkjyfiwJmImAOqLZL7OsoLKuavx+hJjgVV3nLTOjloJyPMFxjUPerGGHrNH0fLU06jjykMLWrERQ==",
"dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "bin": {
- "esbuild": "bin/esbuild"
+ "license": "Apache-2.0",
+ "dependencies": {
+ "b4a": "^1.8.1",
+ "streamx": "^2.25.0",
+ "teex": "^1.0.1"
},
- "engines": {
- "node": ">=18"
+ "peerDependencies": {
+ "bare-abort-controller": "*",
+ "bare-buffer": "*",
+ "bare-events": "*"
},
- "optionalDependencies": {
- "@esbuild/aix-ppc64": "0.28.2",
- "@esbuild/android-arm": "0.28.2",
- "@esbuild/android-arm64": "0.28.2",
- "@esbuild/android-x64": "0.28.2",
- "@esbuild/darwin-arm64": "0.28.2",
- "@esbuild/darwin-x64": "0.28.2",
- "@esbuild/freebsd-arm64": "0.28.2",
- "@esbuild/freebsd-x64": "0.28.2",
- "@esbuild/linux-arm": "0.28.2",
- "@esbuild/linux-arm64": "0.28.2",
- "@esbuild/linux-ia32": "0.28.2",
- "@esbuild/linux-loong64": "0.28.2",
- "@esbuild/linux-mips64el": "0.28.2",
- "@esbuild/linux-ppc64": "0.28.2",
- "@esbuild/linux-riscv64": "0.28.2",
- "@esbuild/linux-s390x": "0.28.2",
- "@esbuild/linux-x64": "0.28.2",
- "@esbuild/netbsd-arm64": "0.28.2",
- "@esbuild/netbsd-x64": "0.28.2",
- "@esbuild/openbsd-arm64": "0.28.2",
- "@esbuild/openbsd-x64": "0.28.2",
- "@esbuild/openharmony-arm64": "0.28.2",
- "@esbuild/sunos-x64": "0.28.2",
- "@esbuild/win32-arm64": "0.28.2",
- "@esbuild/win32-ia32": "0.28.2",
- "@esbuild/win32-x64": "0.28.2"
- }
- },
- "node_modules/escalade": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
- "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
+ "peerDependenciesMeta": {
+ "bare-abort-controller": {
+ "optional": true
+ },
+ "bare-buffer": {
+ "optional": true
+ },
+ "bare-events": {
+ "optional": true
+ }
}
},
- "node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "node_modules/bare-url": {
+ "version": "2.4.5",
+ "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.5.tgz",
+ "integrity": "sha512-K+y9xF1tN+CdPu4qWwr0QiK1Al07eFPGYK5M2pDXcmHdMdgC/tT/bpmMe1hrmRHaidKLkXrC+cRNYf3XVDUhSQ==",
"dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-path": "^3.0.0"
}
},
- "node_modules/eslint": {
- "version": "9.39.4",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz",
- "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==",
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.8.0",
- "@eslint-community/regexpp": "^4.12.1",
- "@eslint/config-array": "^0.21.2",
- "@eslint/config-helpers": "^0.4.2",
- "@eslint/core": "^0.17.0",
- "@eslint/eslintrc": "^3.3.5",
- "@eslint/js": "9.39.4",
- "@eslint/plugin-kit": "^0.4.1",
- "@humanfs/node": "^0.16.6",
- "@humanwhocodes/module-importer": "^1.0.1",
- "@humanwhocodes/retry": "^0.4.2",
- "@types/estree": "^1.0.6",
- "ajv": "^6.14.0",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.6",
- "debug": "^4.3.2",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^8.4.0",
- "eslint-visitor-keys": "^4.2.1",
- "espree": "^10.4.0",
- "esquery": "^1.5.0",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^8.0.0",
- "find-up": "^5.0.0",
- "glob-parent": "^6.0.2",
- "ignore": "^5.2.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.1.5",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.3"
- },
- "bin": {
- "eslint": "bin/eslint.js"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://eslint.org/donate"
- },
- "peerDependencies": {
- "jiti": "*"
- },
- "peerDependenciesMeta": {
- "jiti": {
- "optional": true
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
}
- }
+ ],
+ "license": "MIT"
},
- "node_modules/eslint-config-prettier": {
- "version": "10.1.8",
- "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz",
- "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
+ "node_modules/bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
"dev": true,
- "license": "MIT",
- "bin": {
- "eslint-config-prettier": "bin/cli.js"
- },
- "funding": {
- "url": "https://opencollective.com/eslint-config-prettier"
- },
- "peerDependencies": {
- "eslint": ">=7.0.0"
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "tweetnacl": "^0.14.3"
}
},
- "node_modules/eslint-import-context": {
- "version": "0.1.9",
- "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz",
- "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==",
+ "node_modules/binaryextensions": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz",
+ "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==",
"dev": true,
- "license": "MIT",
+ "license": "Artistic-2.0",
"dependencies": {
- "get-tsconfig": "^4.10.1",
- "stable-hash-x": "^0.2.0"
+ "editions": "^6.21.0"
},
"engines": {
- "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+ "node": ">=4"
},
"funding": {
- "url": "https://opencollective.com/eslint-import-context"
- },
- "peerDependencies": {
- "unrs-resolver": "^1.0.0"
- },
- "peerDependenciesMeta": {
- "unrs-resolver": {
- "optional": true
- }
+ "url": "https://bevry.me/fund"
}
},
- "node_modules/eslint-plugin-bpmn-io": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-bpmn-io/-/eslint-plugin-bpmn-io-2.3.1.tgz",
- "integrity": "sha512-Y4CZcyLVFc5PbZpJxs91S3nZSOCLYNfC2JZQ5MWyGdU/1TxJPG0RFcv58HNxqQP7jKIf85TflXvNCvJX4dPClQ==",
+ "node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
"dev": true,
"license": "MIT",
- "workspaces": [
- "test",
- "test/esm"
- ],
"dependencies": {
- "eslint-plugin-import-x": "^4.16.2",
- "eslint-plugin-mocha": "^11.3.0",
- "eslint-plugin-react": "^7.37.5",
- "globals": "^17.6.0"
- },
- "peerDependencies": {
- "eslint": "^9"
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
}
},
- "node_modules/eslint-plugin-bpmn-io/node_modules/globals": {
- "version": "17.7.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz",
- "integrity": "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==",
+ "node_modules/bl/node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
"dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
"license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
}
},
- "node_modules/eslint-plugin-import-x": {
- "version": "4.17.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.17.1.tgz",
- "integrity": "sha512-4cdstYkKCyjumM2Q9NSI03K8D2a9F4Ssz33K2lv2hQa4KmR9jPLwk3uWGtNvclfqBrPGfGuMBwsGMbe6dMRbfg==",
+ "node_modules/bl/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "^8.56.0",
- "comment-parser": "^1.4.1",
- "debug": "^4.4.1",
- "eslint-import-context": "^0.1.9",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.3 || ^10.1.2",
- "semver": "^7.7.2",
- "stable-hash-x": "^0.2.0",
- "unrs-resolver": "^1.9.2"
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint-plugin-import-x"
- },
- "peerDependencies": {
- "@typescript-eslint/utils": "^8.56.0",
- "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
- "eslint-import-resolver-node": "*"
- },
- "peerDependenciesMeta": {
- "@typescript-eslint/utils": {
- "optional": true
- },
- "eslint-import-resolver-node": {
- "optional": true
- }
+ "node": ">= 6"
}
},
- "node_modules/eslint-plugin-mocha": {
- "version": "11.3.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-11.3.0.tgz",
- "integrity": "sha512-anENwrIwmdvunmmssjMn5a4nTd+mYMkqBlwjksxOECcIThLNhefWJIiTWY7pY/arMQFjNwHQjVOZb6pQ9PrLjg==",
+ "node_modules/boundary": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz",
+ "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==",
"dev": true,
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/bpmn-auto-layout": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/bpmn-auto-layout/-/bpmn-auto-layout-1.3.0.tgz",
+ "integrity": "sha512-ufjMy1MaaZxkQF7f2wY6EL6TnRMSFr/r9eBhp0QvS41UHXW77aQVt65+dn2MmVMlHdyvZyOMNYXO2qYpgX6bQA==",
"license": "MIT",
+ "workspaces": [
+ "example"
+ ],
"dependencies": {
- "@eslint-community/eslint-utils": "^4.4.1",
- "globals": "^15.14.0"
+ "bpmn-moddle": "^10.0.0",
+ "min-dash": "^5.0.0"
},
- "peerDependencies": {
- "eslint": ">=9.0.0"
+ "engines": {
+ "node": ">= 18"
}
},
- "node_modules/eslint-plugin-mocha/node_modules/globals": {
- "version": "15.15.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz",
- "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==",
- "dev": true,
+ "node_modules/bpmn-moddle": {
+ "version": "10.3.1",
+ "resolved": "https://registry.npmjs.org/bpmn-moddle/-/bpmn-moddle-10.3.1.tgz",
+ "integrity": "sha512-xjJ8GzseRkjjM0MX/rODVB6iv+rhGLt8FCHJIovLAjJsDEAUjITfyiJZYczJ4pp3wmesbY3sQR7eRT+q5uroVA==",
"license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "dependencies": {
+ "min-dash": "^5.1.0",
+ "moddle": "^8.2.1",
+ "moddle-xml": "^12.3.1"
}
},
- "node_modules/eslint-plugin-react": {
- "version": "7.37.5",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
- "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
- "dev": true,
+ "node_modules/brace-expansion": {
+ "version": "5.0.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"license": "MIT",
"dependencies": {
- "array-includes": "^3.1.8",
- "array.prototype.findlast": "^1.2.5",
- "array.prototype.flatmap": "^1.3.3",
- "array.prototype.tosorted": "^1.1.4",
- "doctrine": "^2.1.0",
- "es-iterator-helpers": "^1.2.1",
- "estraverse": "^5.3.0",
- "hasown": "^2.0.2",
- "jsx-ast-utils": "^2.4.1 || ^3.0.0",
- "minimatch": "^3.1.2",
- "object.entries": "^1.1.9",
- "object.fromentries": "^2.0.8",
- "object.values": "^1.2.1",
- "prop-types": "^15.8.1",
- "resolve": "^2.0.0-next.5",
- "semver": "^6.3.1",
- "string.prototype.matchall": "^4.0.12",
- "string.prototype.repeat": "^1.0.0"
+ "balanced-match": "^4.0.2"
},
"engines": {
- "node": ">=4"
- },
- "peerDependencies": {
- "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
+ "node": "20 || >=22"
}
},
- "node_modules/eslint-plugin-react/node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/eslint-plugin-react/node_modules/brace-expansion": {
- "version": "1.1.21",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
- "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
+ "node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
"license": "MIT",
"dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
}
},
- "node_modules/eslint-plugin-react/node_modules/minimatch": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
- "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "node_modules/buffer-crc32": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz",
+ "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==",
"dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
+ "license": "MIT",
"engines": {
- "node": "*"
+ "node": ">=8.0.0"
}
},
- "node_modules/eslint-plugin-react/node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
"dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/buildcheck": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.7.tgz",
+ "integrity": "sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==",
+ "dev": true,
+ "optional": true,
+ "engines": {
+ "node": ">=10.0.0"
}
},
- "node_modules/eslint-scope": {
- "version": "8.4.0",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
- "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
+ "node_modules/bundle-name": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
+ "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
"dev": true,
- "license": "BSD-2-Clause",
+ "license": "MIT",
"dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
+ "run-applescript": "^7.0.0"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": ">=18"
},
"funding": {
- "url": "https://opencollective.com/eslint"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/eslint-visitor-keys": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
- "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
+ "node_modules/byline": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz",
+ "integrity": "sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==",
"dev": true,
- "license": "Apache-2.0",
+ "license": "MIT",
"engines": {
- "node": "^20.19.0 || ^22.13.0 || >=24"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
+ "node": ">=0.10.0"
}
},
- "node_modules/eslint/node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "node_modules/cacheable": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz",
+ "integrity": "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "dependencies": {
+ "@cacheable/memory": "^2.2.0",
+ "@cacheable/utils": "^2.5.0",
+ "hookified": "^1.15.0",
+ "keyv": "^5.6.0",
+ "qified": "^0.10.1"
+ }
},
- "node_modules/eslint/node_modules/brace-expansion": {
- "version": "1.1.21",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
- "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
}
},
- "node_modules/eslint/node_modules/eslint-visitor-keys": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
- "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"dev": true,
- "license": "Apache-2.0",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ "node": ">= 0.4"
},
"funding": {
- "url": "https://opencollective.com/eslint"
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/eslint/node_modules/minimatch": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
- "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
+ "node_modules/chai": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-6.3.0.tgz",
+ "integrity": "sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==",
"dev": true,
- "license": "ISC",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/chevrotain": {
+ "version": "13.2.0",
+ "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-13.2.0.tgz",
+ "integrity": "sha512-GTouk5YzgBxlTPCaDn5q0q2EJKkrYmnPF+HmF8v0Qo4r3iyPG7HJivkN1wthCXZcm3sIcZFpGTRovLPNdJNRCA==",
+ "license": "Apache-2.0",
"dependencies": {
- "brace-expansion": "^1.1.7"
+ "@chevrotain/cst-dts-gen": "13.2.0",
+ "@chevrotain/gast": "13.2.0",
+ "@chevrotain/regexp-to-ast": "13.2.0",
+ "@chevrotain/types": "13.2.0",
+ "@chevrotain/utils": "13.2.0"
},
"engines": {
- "node": "*"
+ "node": ">=22.0.0"
}
},
- "node_modules/espree": {
- "version": "10.4.0",
- "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
- "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
+ "node_modules/chevrotain-allstar": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.5.0.tgz",
+ "integrity": "sha512-KV7jVd28Qp4Kg9Ovhwlx5vyucoQxqxB22DLpxqRR2YDsHUHirr/NHAHx5bYk+bhJCD88xrLvOrfjlrrZRVa2Mg==",
+ "license": "MIT",
+ "dependencies": {
+ "lodash-es": "^4.18.1"
+ },
+ "peerDependencies": {
+ "chevrotain": "^13.0.0"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
"dev": true,
- "license": "BSD-2-Clause",
+ "license": "ISC"
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "license": "ISC",
"dependencies": {
- "acorn": "^8.15.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^4.2.1"
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
},
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
+ "node": ">=12"
}
},
- "node_modules/espree/node_modules/eslint-visitor-keys": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
- "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
+ "node_modules/cliui/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
- "license": "Apache-2.0",
+ "license": "MIT",
"engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
+ "node": ">=8"
}
},
- "node_modules/esquery": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
- "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
+ "node_modules/cliui/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "estraverse": "^5.1.0"
- },
- "engines": {
- "node": ">=0.10"
- }
+ "license": "MIT"
},
- "node_modules/esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "node_modules/cliui/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
- "license": "BSD-2-Clause",
+ "license": "MIT",
"dependencies": {
- "estraverse": "^5.2.0"
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
},
"engines": {
- "node": ">=4.0"
+ "node": ">=8"
}
},
- "node_modules/estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "node_modules/cliui/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
- "license": "BSD-2-Clause",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
"engines": {
- "node": ">=4.0"
+ "node": ">=8"
}
},
- "node_modules/estree-walker": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
- "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "node_modules/cliui/node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/estree": "^1.0.0"
- }
- },
- "node_modules/esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "dev": true,
- "license": "BSD-2-Clause",
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
"engines": {
- "node": ">=0.10.0"
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
- "node_modules/event-target-shim": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
- "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+ "node_modules/cockatiel": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz",
+ "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=6"
+ "node": ">=16"
}
},
- "node_modules/events": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
- "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
"license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
"engines": {
- "node": ">=0.8.x"
+ "node": ">=7.0.0"
}
},
- "node_modules/events-universal": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
- "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==",
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "bare-events": "^2.7.0"
- }
+ "license": "MIT"
},
- "node_modules/execa": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
- "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
- "dev": true,
+ "node_modules/commander": {
+ "version": "15.0.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-15.0.0.tgz",
+ "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==",
"license": "MIT",
- "dependencies": {
- "cross-spawn": "^6.0.0",
- "get-stream": "^4.0.0",
- "is-stream": "^1.1.0",
- "npm-run-path": "^2.0.0",
- "p-finally": "^1.0.0",
- "signal-exit": "^3.0.0",
- "strip-eof": "^1.0.0"
- },
"engines": {
- "node": ">=6"
+ "node": ">=22.12.0"
}
},
- "node_modules/execa/node_modules/cross-spawn": {
- "version": "6.0.6",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz",
- "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==",
+ "node_modules/compress-commons": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz",
+ "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "nice-try": "^1.0.4",
- "path-key": "^2.0.1",
- "semver": "^5.5.0",
- "shebang-command": "^1.2.0",
- "which": "^1.2.9"
+ "crc-32": "^1.2.0",
+ "crc32-stream": "^6.0.0",
+ "is-stream": "^2.0.1",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^4.0.0"
},
"engines": {
- "node": ">=4.8"
+ "node": ">= 14"
}
},
- "node_modules/execa/node_modules/path-key": {
+ "node_modules/compress-commons/node_modules/is-stream": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
- "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=4"
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/execa/node_modules/semver": {
- "version": "5.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
- "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
+ "node_modules/concurrently": {
+ "version": "10.0.6",
+ "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-10.0.6.tgz",
+ "integrity": "sha512-qgICXXFp2/3nAebRLmxcINKEXM1mLK3ij/y31P02VTs/KIkddIeC05n73DxOXsXMB9LFSqNU1/na3lDlOhcbIw==",
"dev": true,
- "license": "ISC",
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "5.6.2",
+ "rxjs": "7.8.2",
+ "shell-quote": "1.12.0",
+ "supports-color": "10.2.2",
+ "tree-kill": "1.2.2",
+ "yargs": "18.0.0"
+ },
"bin": {
- "semver": "bin/semver"
+ "conc": "dist/bin/index.js",
+ "concurrently": "dist/bin/index.js"
+ },
+ "engines": {
+ "node": ">=22"
+ },
+ "funding": {
+ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
}
},
- "node_modules/execa/node_modules/shebang-command": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
- "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
+ "node_modules/concurrently/node_modules/ansi-styles": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "shebang-regex": "^1.0.0"
- },
"engines": {
- "node": ">=0.10.0"
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/execa/node_modules/shebang-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
- "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
+ "node_modules/concurrently/node_modules/chalk": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
+ "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=0.10.0"
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
}
},
- "node_modules/execa/node_modules/which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "node_modules/concurrently/node_modules/cliui": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
+ "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==",
"dev": true,
"license": "ISC",
"dependencies": {
- "isexe": "^2.0.0"
+ "string-width": "^7.2.0",
+ "strip-ansi": "^7.1.0",
+ "wrap-ansi": "^9.0.0"
},
- "bin": {
- "which": "bin/which"
- }
- },
- "node_modules/expect-type": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz",
- "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==",
- "dev": true,
- "license": "Apache-2.0",
"engines": {
- "node": ">=12.0.0"
+ "node": ">=20"
}
},
- "node_modules/fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "node_modules/concurrently/node_modules/emoji-regex": {
+ "version": "10.6.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
+ "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
"dev": true,
"license": "MIT"
},
- "node_modules/fast-fifo": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
- "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
+ "node_modules/concurrently/node_modules/string-width": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+ "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^10.3.0",
+ "get-east-asian-width": "^1.0.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/concurrently/node_modules/supports-color": {
+ "version": "10.2.2",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz",
+ "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
},
- "node_modules/fast-glob": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
- "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "node_modules/concurrently/node_modules/wrap-ansi": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
+ "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.8"
+ "ansi-styles": "^6.2.1",
+ "string-width": "^7.0.0",
+ "strip-ansi": "^7.1.0"
},
"engines": {
- "node": ">=8.6.0"
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
- "node_modules/fast-glob/node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "node_modules/concurrently/node_modules/yargs": {
+ "version": "18.0.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz",
+ "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==",
"dev": true,
- "license": "ISC",
+ "license": "MIT",
"dependencies": {
- "is-glob": "^4.0.1"
+ "cliui": "^9.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "string-width": "^7.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^22.0.0"
},
"engines": {
- "node": ">= 6"
+ "node": "^20.19.0 || ^22.12.0 || >=23"
}
},
- "node_modules/fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "node_modules/concurrently/node_modules/yargs-parser": {
+ "version": "22.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz",
+ "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
"dev": true,
- "license": "MIT"
+ "license": "ISC",
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=23"
+ }
},
- "node_modules/fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
"dev": true,
"license": "MIT"
},
- "node_modules/fastq": {
- "version": "1.20.1",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
- "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
+ "node_modules/cpu-features": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz",
+ "integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==",
"dev": true,
- "license": "ISC",
+ "hasInstallScript": true,
+ "optional": true,
"dependencies": {
- "reusify": "^1.0.4"
+ "buildcheck": "~0.0.6",
+ "nan": "^2.19.0"
+ },
+ "engines": {
+ "node": ">=10.0.0"
}
},
- "node_modules/file-entry-cache": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
- "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
+ "node_modules/crc-32": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
+ "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "flat-cache": "^4.0.0"
+ "license": "Apache-2.0",
+ "bin": {
+ "crc32": "bin/crc32.njs"
},
"engines": {
- "node": ">=16.0.0"
+ "node": ">=0.8"
}
},
- "node_modules/fill-range": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
- "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "node_modules/crc32-stream": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz",
+ "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "to-regex-range": "^5.0.1"
+ "crc-32": "^1.2.0",
+ "readable-stream": "^4.0.0"
},
"engines": {
- "node": ">=8"
+ "node": ">= 14"
}
},
- "node_modules/find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
},
"engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": ">= 8"
}
},
- "node_modules/flat-cache": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
- "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "flatted": "^3.2.9",
- "keyv": "^4.5.4"
+ "ms": "^2.1.3"
},
"engines": {
- "node": ">=16"
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
}
},
- "node_modules/flatted": {
- "version": "3.4.2",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
- "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true,
- "license": "ISC"
+ "license": "MIT"
},
- "node_modules/for-each": {
- "version": "0.3.5",
- "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
- "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
+ "node_modules/default-browser": {
+ "version": "5.5.1",
+ "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz",
+ "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "is-callable": "^1.2.7"
+ "bundle-name": "^4.1.0",
+ "default-browser-id": "^5.0.0"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">=18"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/foreground-child": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
- "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+ "node_modules/default-browser-id": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz",
+ "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==",
"dev": true,
- "license": "ISC",
- "dependencies": {
- "cross-spawn": "^7.0.6",
- "signal-exit": "^4.0.1"
- },
+ "license": "MIT",
"engines": {
- "node": ">=14"
+ "node": ">=18"
},
"funding": {
- "url": "https://github.com/sponsors/isaacs"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/foreground-child/node_modules/signal-exit": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
- "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "node_modules/define-lazy-prop": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
+ "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
"dev": true,
- "license": "ISC",
+ "license": "MIT",
"engines": {
- "node": ">=14"
+ "node": ">=12"
},
"funding": {
- "url": "https://github.com/sponsors/isaacs"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/fs-constants": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
- "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/fs-extra": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz",
- "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==",
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "graceful-fs": "^4.2.0",
- "jsonfile": "^6.0.1",
- "universalify": "^2.0.0"
- },
+ "license": "Apache-2.0",
+ "peer": true,
"engines": {
- "node": ">=14.14"
+ "node": ">=8"
}
},
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "node_modules/docker-compose": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-1.5.0.tgz",
+ "integrity": "sha512-O+eD6c63+BJORUWddXA7uAlI6H1KLDPd/aS14k73nXYpFliM48C3xrrKB3sXsR1Fp/rHUZQe7+fJ+QA7+jepyw==",
"dev": true,
- "hasInstallScript": true,
"license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
+ "dependencies": {
+ "yaml": "^2.2.2"
+ },
"engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
- "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">= 6.0.0"
}
},
- "node_modules/function.prototype.name": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
- "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
+ "node_modules/docker-modem": {
+ "version": "5.0.7",
+ "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-5.0.7.tgz",
+ "integrity": "sha512-XJgGhoR/CLpqshm4d3L7rzH6t8NgDFUIIpztYlLHIApeJjMZKYJMz2zxPsYxnejq5h3ELYSw/RBsi3t5h7gNTA==",
"dev": true,
- "license": "MIT",
+ "license": "Apache-2.0",
"dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.3",
- "define-properties": "^1.2.1",
- "functions-have-names": "^1.2.3",
- "hasown": "^2.0.2",
- "is-callable": "^1.2.7"
+ "debug": "^4.1.1",
+ "readable-stream": "^3.5.0",
+ "split-ca": "^1.0.1",
+ "ssh2": "^1.15.0"
},
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/functions-have-names": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">= 8.0"
}
},
- "node_modules/generator-function": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
- "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
+ "node_modules/docker-modem/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
"license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
"engines": {
- "node": ">= 0.4"
+ "node": ">= 6"
}
},
- "node_modules/get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "node_modules/dockerode": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-5.0.1.tgz",
+ "integrity": "sha512-avsq/xk4YPIrn0CgleX5bjT9Y8IT1p9PxrNQ++RBQ2WEyFfHCTDsT9kmyxz+H/axnjAwg8wJWEIuPGOUuNupiA==",
"dev": true,
- "license": "ISC",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@balena/dockerignore": "^1.0.2",
+ "@grpc/grpc-js": "^1.11.1",
+ "@grpc/proto-loader": "^0.7.13",
+ "docker-modem": "^5.0.7",
+ "protobufjs": "^7.3.2",
+ "tar-fs": "^2.1.4"
+ },
"engines": {
- "node": "6.* || 8.* || >= 10.*"
+ "node": ">= 14.17"
}
},
- "node_modules/get-east-asian-width": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
- "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==",
+ "node_modules/dockerode/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
"license": "MIT",
- "engines": {
- "node": ">=18"
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
},
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "engines": {
+ "node": ">= 6"
}
},
- "node_modules/get-intrinsic": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
- "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "node_modules/dockerode/node_modules/tar-fs": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.5.tgz",
+ "integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "call-bind-apply-helpers": "^1.0.2",
- "es-define-property": "^1.0.1",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.1.1",
- "function-bind": "^1.1.2",
- "get-proto": "^1.0.1",
- "gopd": "^1.2.0",
- "has-symbols": "^1.1.0",
- "hasown": "^2.0.2",
- "math-intrinsics": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
}
},
- "node_modules/get-port": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz",
- "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==",
+ "node_modules/dockerode/node_modules/tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"dev": true,
"license": "MIT",
- "engines": {
- "node": ">=8"
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
},
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "engines": {
+ "node": ">=6"
}
},
- "node_modules/get-proto": {
+ "node_modules/dunder-proto": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
- "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "dunder-proto": "^1.0.1",
- "es-object-atoms": "^1.0.0"
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
- "node_modules/get-stream": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
- "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+ "node_modules/eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true,
- "license": "MIT",
+ "license": "MIT"
+ },
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "dev": true,
+ "license": "Apache-2.0",
"dependencies": {
- "pump": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
+ "safe-buffer": "^5.0.1"
}
},
- "node_modules/get-symbol-description": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
- "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
+ "node_modules/editions": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz",
+ "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==",
"dev": true,
- "license": "MIT",
+ "license": "Artistic-2.0",
"dependencies": {
- "call-bound": "^1.0.3",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.6"
+ "version-range": "^4.15.0"
},
"engines": {
- "node": ">= 0.4"
+ "ecmascript": ">= es5",
+ "node": ">=4"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://bevry.me/fund"
}
},
- "node_modules/get-tsconfig": {
- "version": "4.14.0",
- "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz",
- "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==",
+ "node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
+ "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "resolve-pkg-maps": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+ "once": "^1.4.0"
}
},
- "node_modules/glob": {
- "version": "10.5.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
- "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
- "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+ "node_modules/entities": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz",
+ "integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==",
"dev": true,
- "license": "ISC",
- "dependencies": {
- "foreground-child": "^3.1.0",
- "jackspeak": "^3.1.2",
- "minimatch": "^9.0.4",
- "minipass": "^7.1.2",
- "package-json-from-dist": "^1.0.0",
- "path-scurry": "^1.11.1"
- },
- "bin": {
- "glob": "dist/esm/bin.mjs"
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=20.19.0"
},
"funding": {
- "url": "https://github.com/sponsors/isaacs"
+ "url": "https://github.com/fb55/entities?sponsor=1"
}
},
- "node_modules/glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"dev": true,
- "license": "ISC",
- "dependencies": {
- "is-glob": "^4.0.3"
- },
+ "license": "MIT",
"engines": {
- "node": ">=10.13.0"
+ "node": ">= 0.4"
}
},
- "node_modules/glob/node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-module-lexer": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz",
+ "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==",
"dev": true,
"license": "MIT"
},
- "node_modules/glob/node_modules/brace-expansion": {
- "version": "2.1.7",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz",
- "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==",
+ "node_modules/es-object-atoms": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
+ "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "balanced-match": "^1.0.0"
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
}
},
- "node_modules/glob/node_modules/minimatch": {
- "version": "9.0.9",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
- "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
+ "node_modules/esbuild": {
+ "version": "0.28.2",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
+ "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==",
"dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^2.0.2"
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
},
"engines": {
- "node": ">=16 || 14 >=14.17"
+ "node": ">=18"
},
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.28.2",
+ "@esbuild/android-arm": "0.28.2",
+ "@esbuild/android-arm64": "0.28.2",
+ "@esbuild/android-x64": "0.28.2",
+ "@esbuild/darwin-arm64": "0.28.2",
+ "@esbuild/darwin-x64": "0.28.2",
+ "@esbuild/freebsd-arm64": "0.28.2",
+ "@esbuild/freebsd-x64": "0.28.2",
+ "@esbuild/linux-arm": "0.28.2",
+ "@esbuild/linux-arm64": "0.28.2",
+ "@esbuild/linux-ia32": "0.28.2",
+ "@esbuild/linux-loong64": "0.28.2",
+ "@esbuild/linux-mips64el": "0.28.2",
+ "@esbuild/linux-ppc64": "0.28.2",
+ "@esbuild/linux-riscv64": "0.28.2",
+ "@esbuild/linux-s390x": "0.28.2",
+ "@esbuild/linux-x64": "0.28.2",
+ "@esbuild/netbsd-arm64": "0.28.2",
+ "@esbuild/netbsd-x64": "0.28.2",
+ "@esbuild/openbsd-arm64": "0.28.2",
+ "@esbuild/openbsd-x64": "0.28.2",
+ "@esbuild/openharmony-arm64": "0.28.2",
+ "@esbuild/sunos-x64": "0.28.2",
+ "@esbuild/win32-arm64": "0.28.2",
+ "@esbuild/win32-ia32": "0.28.2",
+ "@esbuild/win32-x64": "0.28.2"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
}
},
- "node_modules/globals": {
- "version": "14.0.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
- "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=18"
+ "node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/globalthis": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
- "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+ "node_modules/eslint": {
+ "version": "10.13.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.13.0.tgz",
+ "integrity": "sha512-UohDjD4zSzEwhf58M3O7vc/ycc8O1I7dNlhtD0WxE8Px8EHNJKtUwzBqrzeGhisRuv2ag4sAYswszCJRgKXYUg==",
"dev": true,
"license": "MIT",
+ "workspaces": [
+ "packages/*"
+ ],
"dependencies": {
- "define-properties": "^1.2.1",
- "gopd": "^1.0.1"
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.2",
+ "@eslint/config-array": "^0.23.5",
+ "@eslint/config-helpers": "^0.7.0",
+ "@eslint/core": "^1.2.1",
+ "@eslint/plugin-kit": "^0.7.3",
+ "@humanfs/node": "^0.16.6",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@humanwhocodes/retry": "^0.4.2",
+ "@types/estree": "^1.0.6",
+ "ajv": "^6.14.0",
+ "cross-spawn": "^7.0.6",
+ "debug": "^4.3.2",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^9.1.2",
+ "eslint-visitor-keys": "^5.0.1",
+ "espree": "^11.2.0",
+ "esquery": "^1.7.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "11.1.5 || >11.1.6 <12",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "minimatch": "^10.2.5",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
},
"engines": {
- "node": ">= 0.4"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
}
},
- "node_modules/gopd": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
- "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "node_modules/eslint-config-prettier": {
+ "version": "10.1.8",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz",
+ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
"dev": true,
"license": "MIT",
- "engines": {
- "node": ">= 0.4"
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://opencollective.com/eslint-config-prettier"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
}
},
- "node_modules/graceful-fs": {
- "version": "4.2.11",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
- "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/has-bigints": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
- "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
+ "node_modules/eslint-scope": {
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz",
+ "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==",
"dev": true,
- "license": "MIT",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@types/esrecurse": "^4.3.1",
+ "@types/estree": "^1.0.8",
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
"engines": {
- "node": ">= 0.4"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://opencollective.com/eslint"
}
},
- "node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "node_modules/eslint-visitor-keys": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
"dev": true,
- "license": "MIT",
+ "license": "Apache-2.0",
"engines": {
- "node": ">=8"
- }
- },
- "node_modules/has-property-descriptors": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
- "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-define-property": "^1.0.0"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://opencollective.com/eslint"
}
},
- "node_modules/has-proto": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
- "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
+ "node_modules/espree": {
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz",
+ "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==",
"dev": true,
- "license": "MIT",
+ "license": "BSD-2-Clause",
"dependencies": {
- "dunder-proto": "^1.0.0"
+ "acorn": "^8.16.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^5.0.1"
},
"engines": {
- "node": ">= 0.4"
+ "node": "^20.19.0 || ^22.13.0 || >=24"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://opencollective.com/eslint"
}
},
- "node_modules/has-symbols": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
- "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "node_modules/esquery": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
"dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "estraverse": "^5.1.0"
},
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "engines": {
+ "node": ">=0.10"
}
},
- "node_modules/has-tostringtag": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
- "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
- "license": "MIT",
+ "license": "BSD-2-Clause",
"dependencies": {
- "has-symbols": "^1.0.3"
+ "estraverse": "^5.2.0"
},
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=4.0"
}
},
- "node_modules/hasown": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
- "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "function-bind": "^1.1.2"
- },
+ "license": "BSD-2-Clause",
"engines": {
- "node": ">= 0.4"
+ "node": ">=4.0"
}
},
- "node_modules/hosted-git-info": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
- "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+ "node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dev": true,
- "license": "ISC",
+ "license": "MIT",
"dependencies": {
- "lru-cache": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
+ "@types/estree": "^1.0.0"
}
},
- "node_modules/hosted-git-info/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true,
- "license": "ISC",
- "dependencies": {
- "yallist": "^4.0.0"
- },
+ "license": "BSD-2-Clause",
"engines": {
- "node": ">=10"
+ "node": ">=0.10.0"
}
},
- "node_modules/html-escaper": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
- "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+ "node_modules/event-target-shim": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
},
- "node_modules/http-proxy-agent": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
- "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "agent-base": "^7.1.0",
- "debug": "^4.3.4"
- },
"engines": {
- "node": ">= 14"
+ "node": ">=0.8.x"
}
},
- "node_modules/https-proxy-agent": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
- "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+ "node_modules/events-universal": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
+ "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==",
"dev": true,
- "license": "MIT",
+ "license": "Apache-2.0",
"dependencies": {
- "agent-base": "^7.1.2",
- "debug": "4"
- },
+ "bare-events": "^2.7.0"
+ }
+ },
+ "node_modules/expect-type": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz",
+ "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==",
+ "dev": true,
+ "license": "Apache-2.0",
"engines": {
- "node": ">= 14"
+ "node": ">=12.0.0"
}
},
- "node_modules/ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-fifo": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
+ "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "BSD-3-Clause"
+ "license": "MIT"
},
- "node_modules/ignore": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
- "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "node_modules/file-entry-cache": {
+ "version": "11.1.5",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz",
+ "integrity": "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==",
"dev": true,
"license": "MIT",
- "engines": {
- "node": ">= 4"
+ "dependencies": {
+ "flat-cache": "^6.1.23"
}
},
- "node_modules/import-fresh": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
- "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
"dev": true,
"license": "MIT",
"dependencies": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
},
"engines": {
- "node": ">=6"
+ "node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.8.19"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/internal-slot": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
- "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
+ "node_modules/flat-cache": {
+ "version": "6.1.23",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz",
+ "integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "es-errors": "^1.3.0",
- "hasown": "^2.0.2",
- "side-channel": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
+ "cacheable": "^2.5.0",
+ "flatted": "^3.4.2",
+ "hookified": "^1.15.0"
}
},
- "node_modules/interpret": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
- "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
+ "node_modules/flatted": {
+ "version": "3.4.4",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz",
+ "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==",
"dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.10"
- }
+ "license": "ISC"
},
- "node_modules/is-array-buffer": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
- "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
+ "node_modules/foreground-child": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
"dev": true,
- "license": "MIT",
+ "license": "ISC",
"dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.3",
- "get-intrinsic": "^1.2.6"
+ "cross-spawn": "^7.0.6",
+ "signal-exit": "^4.0.1"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">=14"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/is-async-function": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
- "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
+ "node_modules/foreground-child/node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "async-function": "^1.0.0",
- "call-bound": "^1.0.3",
- "get-proto": "^1.0.1",
- "has-tostringtag": "^1.0.2",
- "safe-regex-test": "^1.1.0"
- },
+ "license": "ISC",
"engines": {
- "node": ">= 0.4"
+ "node": ">=14"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/is-bigint": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
- "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
+ "node_modules/fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fs-extra": {
+ "version": "11.4.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.1.tgz",
+ "integrity": "sha512-KYAb4c9BJQI6QqGKthV68OHe0badztdXJWKo0WtBA9IuCFPTKvE5ZdUBglP833aMjhaSPNO4A5j/EkzZtGlKjA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "has-bigints": "^1.0.2"
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
},
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=14.14"
}
},
- "node_modules/is-boolean-object": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
- "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
+ "hasInstallScript": true,
"license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "has-tostringtag": "^1.0.2"
- },
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "peer": true,
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
- "node_modules/is-callable": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
- "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-core-module": {
- "version": "2.16.2",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz",
- "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==",
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "hasown": "^2.0.3"
- },
+ "license": "ISC",
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": "6.* || 8.* || >= 10.*"
}
},
- "node_modules/is-data-view": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
- "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
+ "node_modules/get-east-asian-width": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
+ "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "get-intrinsic": "^1.2.6",
- "is-typed-array": "^1.1.13"
- },
"engines": {
- "node": ">= 0.4"
+ "node": ">=18"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-date-object": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
- "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "call-bound": "^1.0.2",
- "has-tostringtag": "^1.0.2"
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
@@ -6184,114 +4142,118 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-docker": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
- "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+ "node_modules/get-port": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz",
+ "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==",
"dev": true,
"license": "MIT",
- "bin": {
- "is-docker": "cli.js"
- },
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"dev": true,
"license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
"engines": {
- "node": ">=0.10.0"
+ "node": ">= 0.4"
}
},
- "node_modules/is-finalizationregistry": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
- "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
+ "node_modules/glob": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
+ "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
"dev": true,
- "license": "MIT",
+ "license": "ISC",
"dependencies": {
- "call-bound": "^1.0.3"
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
},
- "engines": {
- "node": ">= 0.4"
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
- "license": "MIT",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
"engines": {
- "node": ">=8"
+ "node": ">=10.13.0"
}
},
- "node_modules/is-generator-function": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
- "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
+ "node_modules/glob/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.4",
- "generator-function": "^2.0.0",
- "get-proto": "^1.0.1",
- "has-tostringtag": "^1.0.2",
- "safe-regex-test": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "license": "MIT"
+ },
+ "node_modules/glob/node_modules/brace-expansion": {
+ "version": "2.1.7",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz",
+ "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
}
},
- "node_modules/is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "node_modules/glob/node_modules/minimatch": {
+ "version": "9.0.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"dev": true,
- "license": "MIT",
+ "license": "ISC",
"dependencies": {
- "is-extglob": "^2.1.1"
+ "brace-expansion": "^2.0.2"
},
"engines": {
- "node": ">=0.10.0"
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/is-inside-container": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
- "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+ "node_modules/globals": {
+ "version": "17.13.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-17.13.0.tgz",
+ "integrity": "sha512-RwMTC61u7hrG3ZJMkZQOK4JLJrKS8QtoTii63EmWvFXHqycY9FObBJQCbsLxSO8kjKhWE5kV1GC+Vb1g3RI0Zg==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "is-docker": "^3.0.0"
- },
- "bin": {
- "is-inside-container": "cli.js"
- },
"engines": {
- "node": ">=14.16"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-map": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
- "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -6301,10 +4263,17 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-negative-zero": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
- "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -6314,186 +4283,207 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "node_modules/hashery": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz",
+ "integrity": "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==",
"dev": true,
"license": "MIT",
+ "dependencies": {
+ "hookified": "^1.15.0"
+ },
"engines": {
- "node": ">=0.12.0"
+ "node": ">=20"
}
},
- "node_modules/is-number-object": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
- "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
+ "node_modules/hasown": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
+ "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "call-bound": "^1.0.3",
- "has-tostringtag": "^1.0.2"
+ "function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-regex": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
- "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
+ "node_modules/hookified": {
+ "version": "1.15.1",
+ "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz",
+ "integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==",
"dev": true,
- "license": "MIT",
+ "license": "MIT"
+ },
+ "node_modules/hosted-git-info": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+ "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+ "dev": true,
+ "license": "ISC",
"dependencies": {
- "call-bound": "^1.0.2",
- "gopd": "^1.2.0",
- "has-tostringtag": "^1.0.2",
- "hasown": "^2.0.2"
+ "lru-cache": "^6.0.0"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">=10"
+ }
+ },
+ "node_modules/hosted-git-info/node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^4.0.0"
},
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "engines": {
+ "node": ">=10"
}
},
- "node_modules/is-set": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
- "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
+ "node_modules/http-proxy-agent": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+ "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
"dev": true,
"license": "MIT",
- "engines": {
- "node": ">= 0.4"
+ "dependencies": {
+ "agent-base": "^7.1.0",
+ "debug": "^4.3.4"
},
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "engines": {
+ "node": ">= 14"
}
},
- "node_modules/is-shared-array-buffer": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
- "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
+ "node_modules/https-proxy-agent": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+ "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "call-bound": "^1.0.3"
+ "agent-base": "^7.1.2",
+ "debug": "4"
},
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">= 14"
}
},
- "node_modules/is-stream": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
- "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=0.10.0"
+ "node": ">= 4"
}
},
- "node_modules/is-string": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
- "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "has-tostringtag": "^1.0.2"
- },
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=0.8.19"
}
},
- "node_modules/is-symbol": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
- "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/is-docker": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+ "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "has-symbols": "^1.1.0",
- "safe-regex-test": "^1.1.0"
+ "bin": {
+ "is-docker": "cli.js"
},
"engines": {
- "node": ">= 0.4"
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-typed-array": {
- "version": "1.1.15",
- "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
- "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "which-typed-array": "^1.1.16"
- },
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=0.10.0"
}
},
- "node_modules/is-weakmap": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
- "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=8"
}
},
- "node_modules/is-weakref": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
- "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "call-bound": "^1.0.3"
+ "is-extglob": "^2.1.1"
},
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=0.10.0"
}
},
- "node_modules/is-weakset": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
- "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
+ "node_modules/is-inside-container": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+ "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "call-bound": "^1.0.3",
- "get-intrinsic": "^1.2.6"
+ "is-docker": "^3.0.0"
+ },
+ "bin": {
+ "is-inside-container": "cli.js"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">=14.16"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-wsl": {
@@ -6512,13 +4502,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/isarray": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
- "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -6526,45 +4509,6 @@
"dev": true,
"license": "ISC"
},
- "node_modules/istanbul-lib-coverage": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
- "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
- "dev": true,
- "license": "BSD-3-Clause",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/istanbul-lib-report": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
- "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "istanbul-lib-coverage": "^3.0.0",
- "make-dir": "^4.0.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/istanbul-reports": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz",
- "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "html-escaper": "^2.0.0",
- "istanbul-lib-report": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/istextorbinary": {
"version": "9.5.0",
"resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz",
@@ -6583,24 +4527,6 @@
"url": "https://bevry.me/fund"
}
},
- "node_modules/iterator.prototype": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz",
- "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "define-data-property": "^1.1.4",
- "es-object-atoms": "^1.0.0",
- "get-intrinsic": "^1.2.6",
- "get-proto": "^1.0.0",
- "has-symbols": "^1.1.0",
- "set-function-name": "^2.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/jackspeak": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
@@ -6617,43 +4543,6 @@
"@pkgjs/parseargs": "^0.11.0"
}
},
- "node_modules/js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/js-yaml": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
- "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/puzrin"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/nodeca"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/json-buffer": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
- "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -6721,22 +4610,6 @@
"npm": ">=6"
}
},
- "node_modules/jsx-ast-utils": {
- "version": "3.3.5",
- "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
- "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "array-includes": "^3.1.6",
- "array.prototype.flat": "^1.3.1",
- "object.assign": "^4.1.4",
- "object.values": "^1.1.6"
- },
- "engines": {
- "node": ">=4.0"
- }
- },
"node_modules/jwa": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
@@ -6761,26 +4634,26 @@
}
},
"node_modules/keyv": {
- "version": "4.5.4",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
- "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz",
+ "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "json-buffer": "3.0.1"
+ "@keyv/serialize": "^1.1.1"
}
},
"node_modules/langium": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/langium/-/langium-4.3.1.tgz",
- "integrity": "sha512-4lmkLHytLXD5pvyL0PKUj1LCNpgzv9s8luH+GbWXHG45QLmO6PlFXrCUghDN5BfcFTlaQyXpXiaSl8A28Xep8w==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/langium/-/langium-4.4.0.tgz",
+ "integrity": "sha512-VFIFtohpsmJeQ+LkaeuUNtyvkklecklI0FSLxFS8JfiGABE9XCpUJwYUNnLk6C2aOyk0w99tNlvd0pmbJ2AW/w==",
"license": "MIT",
"dependencies": {
- "@chevrotain/regexp-to-ast": "~12.0.0",
- "chevrotain": "~12.0.0",
- "chevrotain-allstar": "~0.4.3",
- "vscode-languageserver": "~10.0.1",
- "vscode-languageserver-protocol": "~3.18.1",
+ "@chevrotain/regexp-to-ast": "~13.2.0",
+ "chevrotain": "~13.2.0",
+ "chevrotain-allstar": "~0.5.0",
+ "vscode-languageserver": "~10.1.0",
+ "vscode-languageserver-protocol": "~3.18.2",
"vscode-languageserver-textdocument": "~1.0.13",
"vscode-languageserver-types": "~3.18.0",
"vscode-uri": "~3.1.0"
@@ -6791,18 +4664,18 @@
}
},
"node_modules/langium-cli": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/langium-cli/-/langium-cli-4.3.0.tgz",
- "integrity": "sha512-+TtgkhX8Z3exRBJvTFWV1semhWUCnWMhMP+ZKjpKIeyY6GgnQHehf3ZWyCvVL5T95uqgWZb77aoq9rhI2MPNTA==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/langium-cli/-/langium-cli-4.4.0.tgz",
+ "integrity": "sha512-CSqwKebp8qWa9Y5s1xgEl4qxGPH71Wf4yMXKPuwICoL2yRfVtUl2zpTwF4O5WhYOxnuSpf0rJrxzjQRK5whL7Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"chalk": "~5.6.2",
"commander": "~15.0.0",
- "fs-extra": "~11.3.5",
+ "fs-extra": "~11.4.0",
"jsonschema": "~1.5.0",
- "langium": "~4.3.0",
- "langium-railroad": "~4.3.0",
+ "langium": "~4.4.0",
+ "langium-railroad": "~4.4.0",
"lodash": "~4.18.1"
},
"bin": {
@@ -6827,13 +4700,13 @@
}
},
"node_modules/langium-railroad": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/langium-railroad/-/langium-railroad-4.3.0.tgz",
- "integrity": "sha512-dbuv149MQe8XcgM48FagH22JBaqN0MvN9RRJKBdRQWDeHUYAASliiOtLdMfgOl3kV+nLx7idSc+LLdcBSduvHw==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/langium-railroad/-/langium-railroad-4.4.0.tgz",
+ "integrity": "sha512-5dZINWslRqUkQaVtn+45SdZyOZ2+LwBGrzWKbRkVf76IZPCRTBzbmNYaCFW09Nwl5dMmv+iQvwkUwViljN0hvg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "langium": "~4.3.0",
+ "langium": "~4.4.0",
"railroad-diagrams": "~1.0.0"
}
},
@@ -6910,6 +4783,7 @@
"integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==",
"dev": true,
"license": "MPL-2.0",
+ "peer": true,
"dependencies": {
"detect-libc": "^2.0.3"
},
@@ -6947,6 +4821,7 @@
"os": [
"android"
],
+ "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -6968,6 +4843,7 @@
"os": [
"darwin"
],
+ "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -6989,6 +4865,7 @@
"os": [
"darwin"
],
+ "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -7010,6 +4887,7 @@
"os": [
"freebsd"
],
+ "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -7031,6 +4909,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -7052,6 +4931,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -7073,6 +4953,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -7094,6 +4975,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -7115,6 +4997,7 @@
"os": [
"linux"
],
+ "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -7136,6 +5019,7 @@
"os": [
"win32"
],
+ "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -7157,6 +5041,7 @@
"os": [
"win32"
],
+ "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -7243,13 +5128,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
@@ -7264,19 +5142,6 @@
"dev": true,
"license": "Apache-2.0"
},
- "node_modules/loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- },
- "bin": {
- "loose-envify": "cli.js"
- }
- },
"node_modules/lru-cache": {
"version": "10.4.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
@@ -7285,13 +5150,13 @@
"license": "ISC"
},
"node_modules/magic-string": {
- "version": "0.30.21",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
- "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-1.4.3.tgz",
+ "integrity": "sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jridgewell/sourcemap-codec": "^1.5.5"
+ "@jridgewell/sourcemap-codec": "^1.6.0"
}
},
"node_modules/magicast": {
@@ -7306,22 +5171,6 @@
"source-map-js": "^1.2.1"
}
},
- "node_modules/make-dir": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
- "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "semver": "^7.5.3"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/marked": {
"version": "18.0.13",
"resolved": "https://registry.npmjs.org/marked/-/marked-18.0.13.tgz",
@@ -7345,30 +5194,6 @@
"node": ">= 0.4"
}
},
- "node_modules/merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/micromatch": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
- "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "braces": "^3.0.3",
- "picomatch": "^2.3.1"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
"node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
@@ -7403,16 +5228,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/minimist": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
- "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/minipass": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
@@ -7420,291 +5235,122 @@
"dev": true,
"license": "BlueOak-1.0.0",
"engines": {
- "node": ">=16 || 14 >=14.17"
- }
- },
- "node_modules/mkdirp": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
- "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
- "dev": true,
- "license": "MIT",
- "bin": {
- "mkdirp": "dist/cjs/src/bin.js"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/mkdirp-classic": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
- "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/moddle": {
- "version": "8.2.1",
- "resolved": "https://registry.npmjs.org/moddle/-/moddle-8.2.1.tgz",
- "integrity": "sha512-20qzO/ZpMGO9j9gdQgXk9bfGxb9wA3JKnGth/21YZKODLrZE4RW/uVMIL5pTskYm34Z61DucBEPkq93qByNsBQ==",
- "license": "MIT",
- "dependencies": {
- "min-dash": "^5.1.0"
- }
- },
- "node_modules/moddle-xml": {
- "version": "12.2.0",
- "resolved": "https://registry.npmjs.org/moddle-xml/-/moddle-xml-12.2.0.tgz",
- "integrity": "sha512-kqjdAod5n2v3IVJGudJKRUa1PU/p8GpIb0HbfbVXCppt/MEHtRs+Qi/Q3KTy31JbZCUF9L36mY4wUx7PqqMX4g==",
- "license": "MIT",
- "dependencies": {
- "min-dash": "^5.1.0",
- "saxen": "^11.1.0"
- },
- "engines": {
- "node": ">= 18"
- },
- "peerDependencies": {
- "moddle": ">= 6.2.0"
- }
- },
- "node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/mute-stream": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
- "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
- "dev": true,
- "license": "ISC"
- },
- "node_modules/nan": {
- "version": "2.27.0",
- "resolved": "https://registry.npmjs.org/nan/-/nan-2.27.0.tgz",
- "integrity": "sha512-hC+0LidcL3XE4rp1C4H54KujgXKzbfyTngZTwBByQxsOxCEKZT0MPQ4hOKUH2jU1OYstqdDH4onyHPDzcV0XdQ==",
- "dev": true,
- "license": "MIT",
- "optional": true
- },
- "node_modules/nanoid": {
- "version": "3.3.18",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
- "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "license": "MIT",
- "bin": {
- "nanoid": "bin/nanoid.cjs"
- },
- "engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
- }
- },
- "node_modules/napi-postinstall": {
- "version": "0.3.4",
- "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz",
- "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==",
- "dev": true,
- "license": "MIT",
- "bin": {
- "napi-postinstall": "lib/cli.js"
- },
- "engines": {
- "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/napi-postinstall"
- }
- },
- "node_modules/natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/nice-try": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
- "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/node-exports-info": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz",
- "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "array.prototype.flatmap": "^1.3.3",
- "es-errors": "^1.3.0",
- "object.entries": "^1.1.9",
- "semver": "^6.3.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/node-exports-info/node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/npm-run-path": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
- "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "path-key": "^2.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/npm-run-path/node_modules/path-key": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
- "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
+ "node": ">=16 || 14 >=14.17"
}
},
- "node_modules/object-inspect": {
- "version": "1.13.4",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
- "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "node_modules/mkdirp": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
+ "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
"dev": true,
"license": "MIT",
+ "bin": {
+ "mkdirp": "dist/cjs/src/bin.js"
+ },
"engines": {
- "node": ">= 0.4"
+ "node": ">=10"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "node_modules/mkdirp-classic": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
"dev": true,
+ "license": "MIT"
+ },
+ "node_modules/moddle": {
+ "version": "8.2.1",
+ "resolved": "https://registry.npmjs.org/moddle/-/moddle-8.2.1.tgz",
+ "integrity": "sha512-20qzO/ZpMGO9j9gdQgXk9bfGxb9wA3JKnGth/21YZKODLrZE4RW/uVMIL5pTskYm34Z61DucBEPkq93qByNsBQ==",
"license": "MIT",
- "engines": {
- "node": ">= 0.4"
+ "dependencies": {
+ "min-dash": "^5.1.0"
}
},
- "node_modules/object.assign": {
- "version": "4.1.7",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
- "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
- "dev": true,
+ "node_modules/moddle-xml": {
+ "version": "12.3.1",
+ "resolved": "https://registry.npmjs.org/moddle-xml/-/moddle-xml-12.3.1.tgz",
+ "integrity": "sha512-XbAQDWCG2ZRch3odmQigJ4GwTqrOVBx0+JHEAgdw0U3MkBsWa9LAbO//S5RPdYMcRO87E63r/R/I3CoMef6ncA==",
"license": "MIT",
"dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.3",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0",
- "has-symbols": "^1.1.0",
- "object-keys": "^1.1.1"
+ "min-dash": "^5.1.0",
+ "saxen": "^11.2.0"
},
"engines": {
- "node": ">= 0.4"
+ "node": ">= 18"
},
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "peerDependencies": {
+ "moddle": ">= 6.2.0"
}
},
- "node_modules/object.entries": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz",
- "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==",
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/mute-stream": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/nan": {
+ "version": "2.27.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.27.0.tgz",
+ "integrity": "sha512-hC+0LidcL3XE4rp1C4H54KujgXKzbfyTngZTwBByQxsOxCEKZT0MPQ4hOKUH2jU1OYstqdDH4onyHPDzcV0XdQ==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.4",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.1.1"
+ "optional": true
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.18",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
+ "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "peer": true,
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
},
"engines": {
- "node": ">= 0.4"
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
- "node_modules/object.fromentries": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
- "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-object-atoms": "^1.0.0"
- },
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=0.10.0"
}
},
- "node_modules/object.values": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
- "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.3",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- },
"engines": {
"node": ">= 0.4"
},
@@ -7713,15 +5359,18 @@
}
},
"node_modules/obug": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz",
- "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/obug/-/obug-3.0.0.tgz",
+ "integrity": "sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==",
"dev": true,
"funding": [
"https://github.com/sponsors/sxzz",
"https://opencollective.com/debug"
],
- "license": "MIT"
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ }
},
"node_modules/once": {
"version": "1.4.0",
@@ -7770,34 +5419,6 @@
"node": ">= 0.8.0"
}
},
- "node_modules/own-keys": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
- "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "get-intrinsic": "^1.2.6",
- "object-keys": "^1.1.1",
- "safe-push-apply": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/p-finally": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
- "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -7837,19 +5458,6 @@
"dev": true,
"license": "BlueOak-1.0.0"
},
- "node_modules/parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "callsites": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/parse5": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz",
@@ -7883,13 +5491,6 @@
"node": ">=8"
}
},
- "node_modules/path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/path-scurry": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
@@ -7907,13 +5508,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/pathe": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
- "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
@@ -7926,30 +5520,8 @@
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true,
- "license": "ISC"
- },
- "node_modules/picomatch": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
- "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/possible-typed-array-names": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
- "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- }
+ "license": "ISC",
+ "peer": true
},
"node_modules/postcss": {
"version": "8.5.26",
@@ -7971,6 +5543,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"nanoid": "^3.3.17",
"picocolors": "^1.1.1",
@@ -7991,9 +5564,9 @@
}
},
"node_modules/prettier": {
- "version": "3.9.6",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz",
- "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==",
+ "version": "3.9.10",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.10.tgz",
+ "integrity": "sha512-skGHTH1Yb9QvaTC4hWnRTzEYtCpApF0UMBPz+t/0ZPzP8ihefo/btKd+QA7pUE0fEwA1SbS/NmhyEcstdXOIdA==",
"dev": true,
"license": "MIT",
"bin": {
@@ -8023,18 +5596,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/prop-types": {
- "version": "15.8.1",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
- "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.13.1"
- }
- },
"node_modules/proper-lockfile": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz",
@@ -8110,6 +5671,26 @@
"node": ">=6"
}
},
+ "node_modules/qified": {
+ "version": "0.10.1",
+ "resolved": "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz",
+ "integrity": "sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hookified": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/qified/node_modules/hookified": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz",
+ "integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/qs": {
"version": "6.16.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz",
@@ -8127,27 +5708,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT"
- },
"node_modules/railroad-diagrams": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz",
@@ -8155,13 +5715,6 @@
"dev": true,
"license": "CC0-1.0"
},
- "node_modules/react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/read": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
@@ -8211,103 +5764,25 @@
},
"node_modules/readdir-glob/node_modules/brace-expansion": {
"version": "2.1.7",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz",
- "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/readdir-glob/node_modules/minimatch": {
- "version": "5.1.9",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
- "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/rechoir": {
- "version": "0.6.2",
- "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
- "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
- "dev": true,
- "dependencies": {
- "resolve": "^1.1.6"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/rechoir/node_modules/resolve": {
- "version": "1.22.12",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz",
- "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "is-core-module": "^2.16.1",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/reflect.getprototypeof": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
- "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.9",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
- "get-intrinsic": "^1.2.7",
- "get-proto": "^1.0.1",
- "which-builtin-type": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz",
+ "integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
}
},
- "node_modules/regexp.prototype.flags": {
- "version": "1.5.4",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
- "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
+ "node_modules/readdir-glob/node_modules/minimatch": {
+ "version": "5.1.9",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
+ "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
"dev": true,
- "license": "MIT",
+ "license": "ISC",
"dependencies": {
- "call-bind": "^1.0.8",
- "define-properties": "^1.2.1",
- "es-errors": "^1.3.0",
- "get-proto": "^1.0.1",
- "gopd": "^1.2.0",
- "set-function-name": "^2.0.2"
+ "brace-expansion": "^2.0.1"
},
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=10"
}
},
"node_modules/require-directory": {
@@ -8320,50 +5795,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/resolve": {
- "version": "2.0.0-next.7",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz",
- "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "is-core-module": "^2.16.2",
- "node-exports-info": "^1.6.0",
- "object-keys": "^1.1.1",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/resolve-pkg-maps": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
- "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
- }
- },
"node_modules/retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
@@ -8374,23 +5805,13 @@
"node": ">= 4"
}
},
- "node_modules/reusify": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
- "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
"node_modules/rolldown": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.6.tgz",
"integrity": "sha512-vMM4q3aixf46GiF1Kok8jDPFsEpXgFWGjUHXNkNHNm+Y2adXAG2dbX91jkti3i0ZRsOlcmbuzAz1poObSHCmUA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@oxc-project/types": "=0.147.0",
"@rolldown/pluginutils": "^1.0.0"
@@ -8432,30 +5853,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "queue-microtask": "^1.2.2"
- }
- },
"node_modules/rxjs": {
"version": "7.8.2",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
@@ -8466,26 +5863,6 @@
"tslib": "^2.1.0"
}
},
- "node_modules/safe-array-concat": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz",
- "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.9",
- "call-bound": "^1.0.4",
- "get-intrinsic": "^1.3.0",
- "has-symbols": "^1.1.0",
- "isarray": "^2.0.5"
- },
- "engines": {
- "node": ">=0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -8507,41 +5884,6 @@
],
"license": "MIT"
},
- "node_modules/safe-push-apply": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
- "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "isarray": "^2.0.5"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/safe-regex-test": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
- "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "es-errors": "^1.3.0",
- "is-regex": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -8560,9 +5902,9 @@
}
},
"node_modules/saxen": {
- "version": "11.1.1",
- "resolved": "https://registry.npmjs.org/saxen/-/saxen-11.1.1.tgz",
- "integrity": "sha512-J4BkmJFaM7VgE7pgkFGsNEcqqM3h7+Mz80vfLWFhx7uNOCOXIu6LLjQHYWNejdst3pf/3JUaBIG9+pkk1umlow==",
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/saxen/-/saxen-11.2.0.tgz",
+ "integrity": "sha512-2bG564AAJcm/3vyZC0Uhs/mACrH+4AHMaKHKAB2M5xMqomUZa27FQ7MYaQGFKVcJk/MVzSEQ34A8QZWW+eiWEw==",
"license": "MIT",
"engines": {
"node": ">= 20.12"
@@ -8580,55 +5922,6 @@
"node": ">=10"
}
},
- "node_modules/set-function-length": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
- "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "define-data-property": "^1.1.4",
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2",
- "get-intrinsic": "^1.2.4",
- "gopd": "^1.0.1",
- "has-property-descriptors": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/set-function-name": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
- "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "define-data-property": "^1.1.4",
- "es-errors": "^1.3.0",
- "functions-have-names": "^1.2.3",
- "has-property-descriptors": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/set-proto": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
- "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "dunder-proto": "^1.0.1",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -8653,9 +5946,9 @@
}
},
"node_modules/shell-quote": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.9.0.tgz",
- "integrity": "sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==",
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.12.0.tgz",
+ "integrity": "sha512-PcByqNyT/38F2kDNi006HAMRJaULuBzq/FOsw3qdZvX/GA9W/jamDaRskgHjubHiftXK5sIFxLNkvrXUwcof6Q==",
"dev": true,
"license": "MIT",
"engines": {
@@ -8665,42 +5958,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/shelljs": {
- "version": "0.9.2",
- "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.9.2.tgz",
- "integrity": "sha512-S3I64fEiKgTZzKCC46zT/Ib9meqofLrQVbpSswtjFfAVDW+AZ54WTnAM/3/yENoxz/V1Cy6u3kiiEbQ4DNphvw==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "execa": "^1.0.0",
- "fast-glob": "^3.3.2",
- "interpret": "^1.0.0",
- "rechoir": "^0.6.2"
- },
- "bin": {
- "shjs": "bin/shjs"
- },
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/shx": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/shx/-/shx-0.4.0.tgz",
- "integrity": "sha512-Z0KixSIlGPpijKgcH6oCMCbltPImvaKy0sGH8AkLRXw1KyzpKtaCTizP2xen+hNDqVF4xxgvA0KXSb9o4Q6hnA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "minimist": "^1.2.8",
- "shelljs": "^0.9.2"
- },
- "bin": {
- "shx": "lib/cli.js"
- },
- "engines": {
- "node": ">=18"
- }
- },
"node_modules/side-channel": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz",
@@ -8777,13 +6034,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/siginfo": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
- "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
- "dev": true,
- "license": "ISC"
- },
"node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
@@ -8792,9 +6042,9 @@
"license": "ISC"
},
"node_modules/source-map-js": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
- "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz",
+ "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
@@ -8848,44 +6098,13 @@
"nan": "^2.23.0"
}
},
- "node_modules/stable-hash-x": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz",
- "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12.0.0"
- }
- },
- "node_modules/stackback": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
- "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/std-env": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz",
- "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.3.0.tgz",
+ "integrity": "sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag==",
"dev": true,
"license": "MIT"
},
- "node_modules/stop-iteration-iterator": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
- "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "es-errors": "^1.3.0",
- "internal-slot": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/streamx": {
"version": "2.28.0",
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.0.tgz",
@@ -8949,125 +6168,27 @@
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=8"
- }
- },
- "node_modules/string-width-cjs/node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/string-width-cjs/node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/string.prototype.matchall": {
- "version": "4.0.12",
- "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz",
- "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.3",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.6",
- "es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
- "get-intrinsic": "^1.2.6",
- "gopd": "^1.2.0",
- "has-symbols": "^1.1.0",
- "internal-slot": "^1.1.0",
- "regexp.prototype.flags": "^1.5.3",
- "set-function-name": "^2.0.2",
- "side-channel": "^1.1.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.repeat": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz",
- "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "define-properties": "^1.1.3",
- "es-abstract": "^1.17.5"
- }
- },
- "node_modules/string.prototype.trim": {
- "version": "1.2.10",
- "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
- "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.2",
- "define-data-property": "^1.1.4",
- "define-properties": "^1.2.1",
- "es-abstract": "^1.23.5",
- "es-object-atoms": "^1.0.0",
- "has-property-descriptors": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimend": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
- "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "call-bound": "^1.0.2",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=8"
}
},
- "node_modules/string.prototype.trimstart": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
- "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
+ "node_modules/string-width-cjs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/string-width-cjs/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
+ "ansi-regex": "^5.0.1"
},
"engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": ">=8"
}
},
"node_modules/strip-ansi": {
@@ -9110,29 +6231,6 @@
"node": ">=8"
}
},
- "node_modules/strip-eof": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
- "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/structured-source": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz",
@@ -9143,32 +6241,6 @@
"boundary": "^2.0.0"
}
},
- "node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/tar-fs": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.3.tgz",
@@ -9208,9 +6280,9 @@
}
},
"node_modules/testcontainers": {
- "version": "12.1.0",
- "resolved": "https://registry.npmjs.org/testcontainers/-/testcontainers-12.1.0.tgz",
- "integrity": "sha512-YjDLqIITuhGLMnM10yhg3oV6lIG5IMpz1R1DPBZoOOks83q7i7IVpeSWRTiyl7roozjiyLmwIoLK/KY8OnZmIA==",
+ "version": "12.2.1",
+ "resolved": "https://registry.npmjs.org/testcontainers/-/testcontainers-12.2.1.tgz",
+ "integrity": "sha512-JfbCyOvLdzatwgqUI3AvYCwRW0P5mCkKQVBPO8U5qSH1efC2kHvnfWmi9VHloy1rAFG2MEqWZObRH4bq0gU1kQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -9220,7 +6292,7 @@
"async-lock": "^1.4.1",
"byline": "^5.0.0",
"debug": "^4.4.3",
- "docker-compose": "^1.4.2",
+ "docker-compose": "^1.5.0",
"dockerode": "^5.0.1",
"get-port": "^5.1.1",
"proper-lockfile": "^4.1.2",
@@ -9228,7 +6300,7 @@
"ssh-remote-port-forward": "^1.0.4",
"tar-fs": "^3.1.3",
"tmp": "^0.2.7",
- "undici": "^8.9.0"
+ "undici": "^8.11.2"
},
"engines": {
"node": ">= 22.22"
@@ -9265,16 +6337,19 @@
}
},
"node_modules/tinybench": {
- "version": "2.9.0",
- "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
- "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-6.2.2.tgz",
+ "integrity": "sha512-nIZ2N2dFpjBsg2hgitKu7mA+FvsIJuGJOwysRngmVRRmWgR/UyPjwJj8c/fT/dhm8EkHnF5EOogRf+0Z2qrimA==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.0.0"
+ }
},
"node_modules/tinyexec": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.2.tgz",
- "integrity": "sha512-M/Q0B2cp4K7kynaT/vnED1j8TlLY+Pp7C6Wl2bl/7u/F0mUVwdyOpwomQb8JpYLitHUssAJRmLZdMCGsrx7i+g==",
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz",
+ "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -9330,9 +6405,9 @@
}
},
"node_modules/tinyrainbow": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz",
- "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.2.0.tgz",
+ "integrity": "sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -9349,19 +6424,6 @@
"node": ">=14.14"
}
},
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
"node_modules/tree-kill": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
@@ -9422,84 +6484,6 @@
"node": ">= 0.8.0"
}
},
- "node_modules/typed-array-buffer": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
- "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "es-errors": "^1.3.0",
- "is-typed-array": "^1.1.14"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/typed-array-byte-length": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
- "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.8",
- "for-each": "^0.3.3",
- "gopd": "^1.2.0",
- "has-proto": "^1.2.0",
- "is-typed-array": "^1.1.14"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/typed-array-byte-offset": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
- "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.8",
- "for-each": "^0.3.3",
- "gopd": "^1.2.0",
- "has-proto": "^1.2.0",
- "is-typed-array": "^1.1.15",
- "reflect.getprototypeof": "^1.0.9"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/typed-array-length": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
- "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bind": "^1.0.7",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "is-typed-array": "^1.1.13",
- "possible-typed-array-names": "^1.0.0",
- "reflect.getprototypeof": "^1.0.6"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/typed-rest-client": {
"version": "1.8.11",
"resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz",
@@ -9526,25 +6510,6 @@
"node": ">=14.17"
}
},
- "node_modules/unbox-primitive": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
- "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.3",
- "has-bigints": "^1.0.2",
- "has-symbols": "^1.1.0",
- "which-boxed-primitive": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/underscore": {
"version": "1.13.8",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz",
@@ -9553,9 +6518,9 @@
"license": "MIT"
},
"node_modules/undici": {
- "version": "8.10.1",
- "resolved": "https://registry.npmjs.org/undici/-/undici-8.10.1.tgz",
- "integrity": "sha512-YQ3WlbqjYMmNpdvDH64jAgLjxuAR9+649calDWhbshYaeQGO2bR4nI94ORJmwI3J9YhoKQnpyGOK+0zlWS5N5Q==",
+ "version": "8.12.2",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-8.12.2.tgz",
+ "integrity": "sha512-XtuDWVdqTLr3NAxm2ly9/hU6kUsJOgGh1RASzMBbsw6aWCOaQzHdW+QQDfdERjfJ2V5vL5pRPa4RetO9UfivDg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -9563,9 +6528,9 @@
}
},
"node_modules/undici-types": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz",
- "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==",
+ "version": "8.9.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz",
+ "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==",
"dev": true,
"license": "MIT"
},
@@ -9579,44 +6544,6 @@
"node": ">= 10.0.0"
}
},
- "node_modules/unrs-resolver": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz",
- "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "dependencies": {
- "napi-postinstall": "^0.3.4"
- },
- "funding": {
- "url": "https://opencollective.com/unrs-resolver"
- },
- "optionalDependencies": {
- "@unrs/resolver-binding-android-arm-eabi": "1.12.2",
- "@unrs/resolver-binding-android-arm64": "1.12.2",
- "@unrs/resolver-binding-darwin-arm64": "1.12.2",
- "@unrs/resolver-binding-darwin-x64": "1.12.2",
- "@unrs/resolver-binding-freebsd-x64": "1.12.2",
- "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2",
- "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2",
- "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2",
- "@unrs/resolver-binding-linux-arm64-musl": "1.12.2",
- "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2",
- "@unrs/resolver-binding-linux-loong64-musl": "1.12.2",
- "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2",
- "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2",
- "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2",
- "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2",
- "@unrs/resolver-binding-linux-x64-gnu": "1.12.2",
- "@unrs/resolver-binding-linux-x64-musl": "1.12.2",
- "@unrs/resolver-binding-openharmony-arm64": "1.12.2",
- "@unrs/resolver-binding-wasm32-wasi": "1.12.2",
- "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2",
- "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2",
- "@unrs/resolver-binding-win32-x64-msvc": "1.12.2"
- }
- },
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -9660,6 +6587,7 @@
"integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"lightningcss": "^1.33.0",
"picomatch": "^4.0.5",
@@ -9738,6 +6666,7 @@
"integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -9746,38 +6675,31 @@
}
},
"node_modules/vitest": {
- "version": "4.1.11",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz",
- "integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@vitest/expect": "4.1.11",
- "@vitest/mocker": "4.1.11",
- "@vitest/pretty-format": "4.1.11",
- "@vitest/runner": "4.1.11",
- "@vitest/snapshot": "4.1.11",
- "@vitest/spy": "4.1.11",
- "@vitest/utils": "4.1.11",
- "es-module-lexer": "^2.0.0",
- "expect-type": "^1.3.0",
- "magic-string": "^0.30.21",
- "obug": "^2.1.1",
- "pathe": "^2.0.3",
- "picomatch": "^4.0.3",
- "std-env": "^4.0.0-rc.1",
- "tinybench": "^2.9.0",
- "tinyexec": "^1.0.2",
- "tinyglobby": "^0.2.15",
- "tinyrainbow": "^3.1.0",
- "vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
- "why-is-node-running": "^2.3.0"
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-5.0.5.tgz",
+ "integrity": "sha512-cPODOMF8YnkiiYtDdHo6n4wWmBrOBBbOIYH2d33M4l3CdNn72h+qMmO6uXffUN6A5AZFXNND/d+krS9mgkXRfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/chai": "^5.2.2",
+ "@vitest/mocker": "5.0.5",
+ "chai": "^6.3.0",
+ "es-module-lexer": "^2.3.2",
+ "expect-type": "^1.4.0",
+ "magic-string": "^1.4.3",
+ "obug": "^3.0.0",
+ "picomatch": "^4.0.7",
+ "std-env": "^4.3.0",
+ "tinybench": "^6.2.2",
+ "tinyexec": "^1.3.1",
+ "tinyglobby": "^0.2.17",
+ "why-is-node-running": "3.2.1"
},
"bin": {
"vitest": "vitest.mjs"
},
"engines": {
- "node": "^20.0.0 || ^22.0.0 || >=24.0.0"
+ "node": "^22.12.0 || ^24.0.0 || >=26.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
@@ -9785,16 +6707,16 @@
"peerDependencies": {
"@edge-runtime/vm": "*",
"@opentelemetry/api": "^1.9.0",
- "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
- "@vitest/browser-playwright": "4.1.11",
- "@vitest/browser-preview": "4.1.11",
- "@vitest/browser-webdriverio": "4.1.11",
- "@vitest/coverage-istanbul": "4.1.11",
- "@vitest/coverage-v8": "4.1.11",
- "@vitest/ui": "4.1.11",
+ "@types/node": "^22.0.0 || >=24.0.0",
+ "@vitest/browser-playwright": "5.0.5",
+ "@vitest/browser-preview": "5.0.5",
+ "@vitest/browser-webdriverio": "^5.0.0-beta.5 || >=5.0.0",
+ "@vitest/coverage-istanbul": "5.0.5",
+ "@vitest/coverage-v8": "5.0.5",
+ "@vitest/ui": "5.0.5",
"happy-dom": "*",
"jsdom": "*",
- "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ "vite": "^6.4.0 || ^7.0.0 || ^8.0.0"
},
"peerDependenciesMeta": {
"@edge-runtime/vm": {
@@ -9836,9 +6758,9 @@
}
},
"node_modules/vitest/node_modules/picomatch": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
- "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz",
+ "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -9853,88 +6775,63 @@
"link": true
},
"node_modules/vscode-jsonrpc": {
- "version": "9.0.2",
- "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-9.0.2.tgz",
- "integrity": "sha512-SbQSV9yRemARxeXw6LU5sS6Zq0e9/DgCCX5yelH263ZQWukbTk8EF8fjTrr1dziasf4GwlJbvTwFnTrnQFWZXQ==",
+ "version": "9.0.3",
+ "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-9.0.3.tgz",
+ "integrity": "sha512-qETYf9PCl1lVfwR+oBmMfc4vP2nqLNA35ABxorw3j06+xlKRgDVxbLgKm4Y/xPL0YWdeDjLoI4ImICIT3nB0zQ==",
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/vscode-languageclient": {
- "version": "10.1.1",
- "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-10.1.1.tgz",
- "integrity": "sha512-EbwIF+KUbwxD5jumQNpiBCv7BJM3Rierv4hcbw/p5jdsnwFFpR/B2VmwqfH4p5XsK46nkH3ugA3WtwJekHHJEw==",
+ "version": "10.1.2",
+ "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-10.1.2.tgz",
+ "integrity": "sha512-cOv5SMvtAhfVeo5m2r9L2rVHAD0J5CFOsmvH1WgNmPaI61VYjJNc3XUDLOKeFSDtWoAXIEoK6KetuBEL/3hErg==",
"license": "MIT",
"dependencies": {
"minimatch": "^10.2.6",
"semver": "^7.8.1",
- "vscode-languageserver-protocol": "3.18.3",
- "vscode-languageserver-textdocument": "1.0.14"
+ "vscode-languageserver-protocol": "3.18.4",
+ "vscode-languageserver-textdocument": "1.0.15"
},
"engines": {
"vscode": "^1.91.0"
}
},
"node_modules/vscode-languageserver": {
- "version": "10.0.1",
- "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-10.0.1.tgz",
- "integrity": "sha512-hfERoZvpaHWzQa7t5mMIrHkEOhF7aTs1dpktem0TW/Xs4QZD7NtcHjIq/aE1CZJEj6Rb8LSGUkBhvTRDdpyGig==",
+ "version": "10.1.2",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-10.1.2.tgz",
+ "integrity": "sha512-pXPWde3RytdeBVEs6PulOOT5OpeXC5GkWRpcT11f5rNn41jviQsAYPyAqJ/0oVGETQLKPJtYbHNiMPlfLb0NTQ==",
"license": "MIT",
"dependencies": {
- "vscode-languageserver-protocol": "3.18.1"
+ "vscode-languageserver-protocol": "3.18.4"
},
"bin": {
"installServerIntoExtension": "bin/installServerIntoExtension"
}
},
"node_modules/vscode-languageserver-protocol": {
- "version": "3.18.3",
- "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.18.3.tgz",
- "integrity": "sha512-DF49+WeV5py4zO5hhobp60jjsDSK0lAqA0OuKBLBvp423HPWQcCbhZz3JgyfIewsEz2f8U+X75xNIFHdiXZm2w==",
+ "version": "3.18.4",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.18.4.tgz",
+ "integrity": "sha512-CCXbyr99dafRJzJH/0Ryk7ly5T8XPmSR0//OuF2w4m+9JiOin7zcAT5iET8GRE7Z9taFBejb3GbM0a0mbjdbrg==",
"license": "MIT",
"dependencies": {
- "vscode-jsonrpc": "9.0.2",
- "vscode-languageserver-types": "3.18.3"
+ "vscode-jsonrpc": "9.0.3",
+ "vscode-languageserver-types": "3.18.4"
}
},
- "node_modules/vscode-languageserver-protocol/node_modules/vscode-languageserver-types": {
- "version": "3.18.3",
- "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.18.3.tgz",
- "integrity": "sha512-XIlzJ7Qp/jzSI1ds7/FwPAWrPeTZA7pAtlW4hdJ1J6xXWJL6dR9QYnDhJOdLzdKhUQ5Mm6mvUMw+3DcOQQasPw==",
- "license": "MIT"
- },
"node_modules/vscode-languageserver-textdocument": {
- "version": "1.0.14",
- "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.14.tgz",
- "integrity": "sha512-EQyqJMi552E4ZTf46izQ4Fj6XquqxCySR3J5ZSD1SisMf6RfpeOWHxGBE8Gr6V0/3GHIGdAzDn8F8+1nTGCnoQ==",
+ "version": "1.0.15",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.15.tgz",
+ "integrity": "sha512-Gsfr9S8LU3S6885cS+NaleasJ0n3V5y/SOTqHCifQiXWFw3G9w9/YItDfwHrlCz+dSZWWZ8ilYVMcJe7Sz7Sxw==",
"license": "MIT"
},
"node_modules/vscode-languageserver-types": {
- "version": "3.18.0",
- "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.18.0.tgz",
- "integrity": "sha512-8TsGPNMIMiiBdkORgRSvLjuiEIiAFtO+KssmYWxQ+uSVvlf7RjK8YKCOjPzZ+YA04jXEV7+7LvkSmHkhpNS99g==",
+ "version": "3.18.4",
+ "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.18.4.tgz",
+ "integrity": "sha512-nQsacoiijvl0fRf2q28uFDrAVwRhdCa3QveiF7/CX0r18mLR5FU/1WskSsCKOjmEbtteKUnY8x8Yzxop+k0zwg==",
"license": "MIT"
},
- "node_modules/vscode-languageserver/node_modules/vscode-jsonrpc": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-9.0.0.tgz",
- "integrity": "sha512-+VvMmQPJhtvJ+8O+zu2JKIRiLxXF8NW7krWgyMGeOHrp4Cn23T5hc0v2LknNeopDOB70wghHAds7mKtcZ0I4Sg==",
- "license": "MIT",
- "engines": {
- "node": ">=14.0.0"
- }
- },
- "node_modules/vscode-languageserver/node_modules/vscode-languageserver-protocol": {
- "version": "3.18.1",
- "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.18.1.tgz",
- "integrity": "sha512-RTiiVHdpxpYcJVI5sq6S5TLjQ4WDR/rBrIWru+kPXe6sGQ9PFQ3GamrTKLvPqbR4ylr1SoodhmcqbFII0WXVuw==",
- "license": "MIT",
- "dependencies": {
- "vscode-jsonrpc": "9.0.0",
- "vscode-languageserver-types": "3.18.0"
- }
- },
"node_modules/vscode-uri": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz",
@@ -9957,110 +6854,17 @@
"node": ">= 8"
}
},
- "node_modules/which-boxed-primitive": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
- "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-bigint": "^1.1.0",
- "is-boolean-object": "^1.2.1",
- "is-number-object": "^1.1.1",
- "is-string": "^1.1.1",
- "is-symbol": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/which-builtin-type": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
- "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "call-bound": "^1.0.2",
- "function.prototype.name": "^1.1.6",
- "has-tostringtag": "^1.0.2",
- "is-async-function": "^2.0.0",
- "is-date-object": "^1.1.0",
- "is-finalizationregistry": "^1.1.0",
- "is-generator-function": "^1.0.10",
- "is-regex": "^1.2.1",
- "is-weakref": "^1.0.2",
- "isarray": "^2.0.5",
- "which-boxed-primitive": "^1.1.0",
- "which-collection": "^1.0.2",
- "which-typed-array": "^1.1.16"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/which-collection": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
- "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-map": "^2.0.3",
- "is-set": "^2.0.3",
- "is-weakmap": "^2.0.2",
- "is-weakset": "^2.0.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/which-typed-array": {
- "version": "1.1.21",
- "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.21.tgz",
- "integrity": "sha512-zbRA8cVm6io/d5W8uIe2hblzN76/Wm3v/yiythQvr+dpBWeqhPSWIDNj4zOyHi4zKbMK6DN34Xsr9jPHJERAEw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.9",
- "call-bound": "^1.0.4",
- "for-each": "^0.3.5",
- "get-proto": "^1.0.1",
- "gopd": "^1.2.0",
- "has-tostringtag": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/why-is-node-running": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
- "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-3.2.1.tgz",
+ "integrity": "sha512-Tb2FUhB4vUsGQlfSquQLYkApkuPAFQXGFzxWKHHumVz2dK+X1RUm/HnID4+TfIGYJ1kTcwOaCk/buYCEJr6YjQ==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "siginfo": "^2.0.0",
- "stackback": "0.0.2"
- },
"bin": {
"why-is-node-running": "cli.js"
},
"engines": {
- "node": ">=8"
+ "node": ">=20.11"
}
},
"node_modules/word-wrap": {
@@ -10385,20 +7189,20 @@
},
"packages/cli": {
"name": "@bpmn-script/cli",
- "version": "0.0.1",
+ "version": "0.1.0",
"license": "Apache-2.0",
"dependencies": {
- "@bpmn-script/language": "0.0.1",
- "@bpmn-script/transform": "*",
- "chalk": "^5.3.0",
+ "@bpmn-script/language": "0.1.0",
+ "@bpmn-script/transform": "0.1.0",
+ "chalk": "^6.0.1",
"commander": "^15.0.0",
- "langium": "^4.3.1"
+ "langium": "^4.4.0"
},
"bin": {
"bpmns": "bin/cli.js"
},
"devDependencies": {
- "vitest": "^4.1.11"
+ "vitest": "^5.0.5"
},
"engines": {
"node": ">=22.0.0",
@@ -10406,12 +7210,12 @@
}
},
"packages/cli/node_modules/chalk": {
- "version": "5.6.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
- "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-6.0.1.tgz",
+ "integrity": "sha512-/Ce6KNm3vIbWdMlNna6RVIZ/ICQxnJxCicet5LBKK9ZffBkqzDw0xh9EiKSljdRtiIQ1S1z4YgcscUUGzNCWrA==",
"license": "MIT",
"engines": {
- "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ "node": ">=22"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
@@ -10419,59 +7223,62 @@
},
"packages/extension": {
"name": "vscode-bpmnscript",
- "version": "0.0.1",
+ "version": "0.1.0",
"license": "Apache-2.0",
"dependencies": {
- "@bpmn-script/language": "0.0.1",
- "@bpmn-script/transform": "0.0.1",
- "vscode-languageclient": "~10.1.1"
+ "@bpmn-script/language": "0.1.0",
+ "@bpmn-script/transform": "0.1.0",
+ "langium": "^4.4.0",
+ "vscode-languageclient": "~10.1.2"
},
"devDependencies": {
"@types/vscode": "~1.134.0",
"@vscode/vsce": "^4.0.0",
- "concurrently": "^10.0.5",
+ "concurrently": "^10.0.6",
"esbuild": "~0.28.2",
- "vitest": "^4.1.11"
+ "vitest": "^5.0.5"
},
"engines": {
"vscode": "^1.134.0"
}
},
+ "packages/extension/node_modules/@types/vscode": {
+ "version": "1.134.0",
+ "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.134.0.tgz",
+ "integrity": "sha512-NDEu0hg4sF7+vvFsADsktqUJ6f80LHSZvVK2Ovo1XiQ0/VHck1O3zst+ZZyVA/uvz6vo6LcuoqU2q48YMqOwWw==",
+ "dev": true,
+ "license": "MIT"
+ },
"packages/language": {
"name": "@bpmn-script/language",
- "version": "0.0.1",
+ "version": "0.1.0",
"license": "Apache-2.0",
"dependencies": {
- "langium": "^4.3.1",
+ "langium": "^4.4.0",
"vscode-languageserver-types": "^3.18.3"
},
"devDependencies": {
- "langium-cli": "^4.3.0",
- "vitest": "^4.1.11"
+ "langium-cli": "^4.4.0",
+ "vitest": "^5.0.5"
},
"engines": {
"node": ">=22.0.0",
"npm": ">=10.2.3"
}
},
- "packages/language/node_modules/vscode-languageserver-types": {
- "version": "3.18.3",
- "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.18.3.tgz",
- "integrity": "sha512-XIlzJ7Qp/jzSI1ds7/FwPAWrPeTZA7pAtlW4hdJ1J6xXWJL6dR9QYnDhJOdLzdKhUQ5Mm6mvUMw+3DcOQQasPw==",
- "license": "MIT"
- },
"packages/transform": {
"name": "@bpmn-script/transform",
- "version": "0.0.1",
+ "version": "0.1.0",
"license": "Apache-2.0",
"dependencies": {
- "@bpmn-script/language": "*",
- "bpmn-auto-layout": "^1.2.0",
- "bpmn-moddle": "^10.2.0",
+ "@bpmn-script/language": "0.1.0",
+ "bpmn-auto-layout": "^1.3.0",
+ "bpmn-moddle": "^10.3.1",
+ "langium": "^4.4.0",
"saxen": "^11.1.0"
},
"devDependencies": {
- "vitest": "^4.1.11"
+ "vitest": "^5.0.5"
},
"engines": {
"node": ">=22.0.0",
@@ -10479,14 +7286,14 @@
}
},
"tests": {
- "version": "0.0.1",
+ "version": "0.1.0",
"license": "Apache-2.0",
"devDependencies": {
- "@bpmn-script/language": "0.0.1",
- "@bpmn-script/transform": "0.0.1",
- "langium": "^4.3.1",
- "testcontainers": "^12.1.0",
- "vitest": "^4.1.11",
+ "@bpmn-script/language": "0.1.0",
+ "@bpmn-script/transform": "0.1.0",
+ "langium": "^4.4.0",
+ "testcontainers": "^12.2.1",
+ "vitest": "^5.0.5",
"vscode-languageserver-types": "^3.18.0"
},
"engines": {
diff --git a/package.json b/package.json
index 0ea6c49..f30ea54 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "bpmn-script-workspace",
"description": "Write executable business processes as text, compile to BPMN 2.0 XML, and read existing BPMN files back as text.",
- "version": "0.0.1",
+ "version": "0.1.0",
"license": "Apache-2.0",
"repository": {
"type": "git",
@@ -25,14 +25,14 @@
"test": "npm run test --workspaces --if-present"
},
"devDependencies": {
- "@types/node": "^26.4.0",
- "@typescript-eslint/parser": "^8.69.0",
- "@vitest/coverage-v8": "^4.1.11",
- "eslint": "^9.0.0",
+ "@eslint/js": "^10.0.1",
+ "@types/node": "^26.6.5",
+ "@typescript-eslint/parser": "^8.71.2",
+ "@vitest/coverage-v8": "^5.0.5",
+ "eslint": "^10.13.0",
"eslint-config-prettier": "^10.1.8",
- "eslint-plugin-bpmn-io": "^2.3.1",
- "prettier": "^3.9.6",
- "shx": "~0.4.0",
+ "globals": "^17.13.0",
+ "prettier": "^3.9.10",
"typescript": "~6.0.0"
},
"workspaces": [
diff --git a/packages/cli/README.md b/packages/cli/README.md
index 8721bb7..ef60d57 100644
--- a/packages/cli/README.md
+++ b/packages/cli/README.md
@@ -1,12 +1,11 @@
# bpmns CLI
-The `bpmns` binary, for compiling and decompiling BPMNscript files from a terminal.
+The `bpmns` command compiles and decompiles BPMNscript files from a terminal.
+The subcommand names are easy to get backwards: `build` compiles BPMNscript to BPMN, and `parse` goes the other way.
This package holds no transformation logic.
-It reads a file, hands it to `@bpmn-script/language` to parse and validate and to `@bpmn-script/transform` to convert, prints whatever went wrong, and writes the result.
-What's left is argument handling, file I/O, and turning failures into readable messages and exit codes.
-
-The two subcommand names are easy to get backwards: `build` compiles DSL to BPMN, `parse` goes the other way.
+It reads a file, hands it to `@bpmn-script/language` to parse and validate and to `@bpmn-script/transform` to convert, prints what went wrong, and writes the result.
+It is not meant to be imported; use those two packages directly.
## Usage
@@ -24,25 +23,35 @@ bpmns parse invoice-approval.bpmn
bpmns parse invoice-approval.bpmn -o invoice-approval.bpmnscript
```
-`build` writes BPMN 2.0 XML with generated diagram interchange data.
-When the layout library cannot place the graph, `build` writes the document without diagram data instead, prints `Warning: no diagram could be drawn for this process (...); the file deploys but opens without shapes in a modeler` to stderr, and still exits `0`, since Operaton deploys such a file unchanged (`BpmnParse.parseDiagramInterchangeElements` reads a diagram only when one is present).
-`parse` writes `.bpmnscript` source.
+From a clone of the repo, run it as `npx bpmns` after `npm run build`.
+
+`build` writes BPMN 2.0 XML with a generated diagram.
+When the layout library can't place the graph, `build` writes the document without a diagram, prints `Warning: no diagram could be drawn for this process` with notes naming the cause, and still exits `0`, since Operaton deploys such a file unchanged.
+
+`parse` writes `.bpmnscript` source and then prints two kinds of warning: what the import dropped or changed, and what the printer couldn't carry into the script.
+Some of these bear on what a rebuilt document runs, so read them before running `build` on the output.
+`parse` then builds the script it just wrote and lists every error `build` would report, still exiting `0`.
+The import and print rules behind those warnings are in [packages/transform/README.md](../transform/README.md#the-import-contract).
+
+## Exit codes
-Exit codes are `0` for success, `1` for validation errors on `build` or a refused BPMN construct on `parse`, and `2` for an I/O problem or input that cannot be read as BPMN XML.
-Both directions report non-fatal warnings on stderr without changing the exit code, so an undeclared variable reference on compile, or a dropped Operaton extension attribute or lane on import, is warned about but still produces a file.
-`parse` reports what the print hop could not carry into the script as well: some of those warnings bear on what a recompiled document runs, and some on whether the script builds back at all, so read them before running `build` on the output.
-After those warnings, `parse` also re-validates the script it just wrote and reports every error `build` would draw from it, still exiting `0` and still writing the file.
-The roundtripping section of the root [README](../../README.md#roundtripping-bpmn-xml---bpmnscript) walks through both hops.
-A BPMN construct the DSL cannot express is the exception: `parse` exits `1` with a message naming the construct and writes nothing.
+| Code | Meaning |
+| ---- | -------------------------------------------------------------------------------------------------- |
+| `0` | Success, with or without warnings |
+| `1` | Validation errors or no process on `build`, a BPMN construct the language can't express on `parse` |
+| `2` | A file or path problem, or input that can't be read as BPMN XML |
+| `3` | An unexpected exception inside a transform, which is a bug in `bpmns` |
-Both subcommands read a file from disk; neither one reads stdin.
-An `-o` equal to the input path always exits `2` before anything is touched, `--force` included: there is no output left to write to once it's the same file as the source.
-An existing output file at a different path is left alone unless you pass `--force`; without it, the command exits `2` instead of overwriting it.
-An `-o` that names an existing directory writes into it under the input's own basename.
-`build` refuses a file that is not `.bpmnscript` with exit `2` and a source with no process with exit `1`; `parse` refuses a file it cannot read as BPMN XML, an empty or non-XML one included, with exit `2`.
+A command that exits `1` writes nothing.
+Every message opens with a headline naming what is wrong and where, with its `note:` and `help:` lines indented beneath it.
-The package is not meant to be imported programmatically.
-Import `@bpmn-script/transform` for the transforms and `@bpmn-script/language` for the Langium services.
+## Files and paths
+
+- Both subcommands read a file from disk, never stdin.
+- `build` takes only a `.bpmnscript` file; `parse` takes any file that reads as BPMN XML.
+- An existing output file is left alone unless you pass `--force`.
+- An `-o` naming the input file itself always exits `2`, even with `--force`.
+- An `-o` naming an existing directory writes into it under the input's basename.
## Build and test
@@ -65,8 +74,3 @@ npm test
| `src/parse.ts` | `parseAction`: read `.bpmn`, `xmlToIr`, `irToDsl`, write `.bpmnscript` |
| `src/util.ts` | Shared by both actions: path guards, `buildDocument`, `CLI_VERSION` |
| `bin/cli.js` | Node entry script; imports the compiled `out/main.js` and runs it |
-
-## Dependencies on other packages
-
-- `@bpmn-script/transform` (workspace) for all four transform functions
-- `@bpmn-script/language` (workspace) for the Langium services that parse `.bpmnscript`
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 6f49527..e796085 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,7 +1,7 @@
{
"name": "@bpmn-script/cli",
"description": "Command line interface compiling BPMNscript to BPMN 2.0 XML and back",
- "version": "0.0.1",
+ "version": "0.1.0",
"license": "Apache-2.0",
"repository": {
"type": "git",
@@ -22,20 +22,21 @@
"bpmns": "./bin/cli.js"
},
"scripts": {
- "clean": "shx rm -fr *.tsbuildinfo out",
+ "prepack": "node -e \"fs.cpSync('../../LICENSE', 'LICENSE')\"",
+ "clean": "node -e \"for (const f of [...fs.globSync('*.tsbuildinfo'), 'out']) fs.rmSync(f, { recursive: true, force: true })\"",
"build": "tsc -p tsconfig.json",
"build:clean": "npm run clean && npm run build",
"typecheck": "tsc -b tsconfig.test.json",
"test": "vitest run"
},
"dependencies": {
- "@bpmn-script/transform": "*",
- "@bpmn-script/language": "0.0.1",
- "chalk": "^5.3.0",
+ "@bpmn-script/language": "0.1.0",
+ "@bpmn-script/transform": "0.1.0",
+ "chalk": "^6.0.1",
"commander": "^15.0.0",
- "langium": "^4.3.1"
+ "langium": "^4.4.0"
},
"devDependencies": {
- "vitest": "^4.1.11"
+ "vitest": "^5.0.5"
}
}
diff --git a/packages/cli/src/build.ts b/packages/cli/src/build.ts
index 0cb26be..7dfffe4 100644
--- a/packages/cli/src/build.ts
+++ b/packages/cli/src/build.ts
@@ -17,9 +17,12 @@ import {
CLI_VERSION,
type CommandOptions,
buildDocument,
+ diagnosticsOf,
fail,
+ failInternal,
formatDiagnostic,
guardOutputPath,
+ indentNotes,
resolveInputPath,
resolveOutputPath,
warn,
@@ -38,8 +41,8 @@ export async function buildAction(
if (!extensions.includes(path.extname(resolvedInput))) {
fail(
2,
- `Error: expected a file with one of these extensions: ${extensions.join(', ')}; ` +
- 'a .bpmn file is decompiled with `bpmns parse`',
+ `Error: expected a file with one of these extensions: ${extensions.join(', ')}\n` +
+ " help: decompile a .bpmn file with 'bpmns parse'",
);
}
@@ -53,9 +56,7 @@ export async function buildAction(
fail(2, `Error: failed to parse ${fileName}: ${(err as Error).message}`);
}
- const errors = (document.diagnostics ?? []).filter(
- (d) => d.severity === DiagnosticSeverity.Error,
- );
+ const errors = diagnosticsOf(document, DiagnosticSeverity.Error);
if (errors.length > 0) {
console.error(chalk.red('Validation errors:'));
for (const diag of errors) {
@@ -68,12 +69,9 @@ export async function buildAction(
const ast = document.parseResult.value as Model;
if (ast.processes.length === 0) fail(1, `Error: ${NO_PROCESS_MESSAGE}`);
- const warnings = (document.diagnostics ?? []).filter(
- (d) => d.severity === DiagnosticSeverity.Warning,
- );
- for (const diag of warnings) {
+ for (const diag of diagnosticsOf(document, DiagnosticSeverity.Warning)) {
warn(
- `Warning: line ${diag.range.start.line + 1}: ${Diagnostic.getMessageString(diag)}`,
+ `Warning: line ${diag.range.start.line + 1}: ${indentNotes(Diagnostic.getMessageString(diag))}`,
);
}
@@ -81,20 +79,20 @@ export async function buildAction(
try {
ir = astToIr(ast);
} catch (err) {
- fail(1, `Error: ${(err as Error).message}`);
+ failInternal(err);
}
let xml: string;
try {
xml = await irToXml(ir, { exporterVersion: CLI_VERSION });
} catch (err) {
- if (!(err instanceof LayoutError)) {
- fail(1, `Error: ${(err as Error).message}`);
- }
+ if (!(err instanceof LayoutError)) failInternal(err);
// Operaton deploys the document without a diagram.
xml = err.xml;
warn(
- `Warning: no diagram could be drawn for this process (${err.message}); the file deploys but opens without shapes in a modeler`,
+ 'Warning: no diagram could be drawn for this process\n' +
+ ` note: ${err.message}\n` +
+ ' note: the file deploys, but opens without shapes in a modeler',
);
}
diff --git a/packages/cli/src/parse.ts b/packages/cli/src/parse.ts
index b01a83f..cac71cf 100644
--- a/packages/cli/src/parse.ts
+++ b/packages/cli/src/parse.ts
@@ -8,18 +8,18 @@ import {
EMPTY_INPUT_MESSAGE,
readableParseError,
xmlInputProblem,
- SERVICE_TASK_FORM_ATTRIBUTES,
UnsupportedConstructError,
- UnsupportedServiceTaskFormError,
- UnsupportedElementError,
} from '@bpmn-script/transform';
import type { ImportWarning, PrintWarning } from '@bpmn-script/transform';
import {
type CommandOptions,
buildDocument,
+ diagnosticsOf,
fail,
+ failInternal,
formatDiagnostic,
guardOutputPath,
+ indentNotes,
resolveInputPath,
resolveOutputPath,
warn,
@@ -46,7 +46,7 @@ export async function parseAction(
if (problem !== undefined) {
fail(
2,
- `Error: ${problem}; a .bpmnscript file is built with \`bpmns build\``,
+ `Error: ${problem}\n help: build a .bpmnscript file with 'bpmns build'`,
);
}
@@ -55,31 +55,13 @@ export async function parseAction(
try {
({ ir, warnings } = await xmlToIr(xml));
} catch (err) {
- // Subclasses first: they all extend UnsupportedConstructError.
- if (err instanceof UnsupportedServiceTaskFormError) {
- fail(
- 1,
- `Error: unsupported ${err.subject.toLowerCase()} form in ${fileName}:\n` +
- ` ${err.message}\n` +
- ` The attributes are ${SERVICE_TASK_FORM_ATTRIBUTES}.`,
- );
- }
- if (err instanceof UnsupportedElementError) {
- fail(
- 1,
- `Error: unsupported BPMN element in ${fileName}:\n ${err.message}`,
- );
- }
if (err instanceof UnsupportedConstructError) {
- fail(
- 1,
- `Error: unsupported BPMN construct in ${fileName}:\n ${err.message}`,
- );
+ fail(1, `Error: ${fileName}: ${indentNotes(err.message)}`);
}
fail(
2,
`Error: failed to parse ${fileName}: ` +
- readableParseError((err as Error).message, xml),
+ indentNotes(readableParseError((err as Error).message, xml)),
);
}
@@ -88,26 +70,23 @@ export async function parseAction(
try {
({ source: dsl, warnings: printWarnings } = irToDsl(ir));
} catch (err) {
- fail(2, `Error: ${(err as Error).message}`);
+ failInternal(err);
}
await writeOutput(outPath, dsl);
console.log(chalk.green(`Parsed: ${outPath}`));
- // Several messages do not name their step, so the id tells them apart.
for (const w of [...warnings, ...printWarnings]) {
- warn(`Warning: ${w.elementId}: ${w.message}`);
+ warn(`Warning: ${indentNotes(w.message)}`);
}
// Nothing above runs the validator, so rebuilding the written script is what catches an error.
- const rebuilt = await buildDocument(outPath);
- const buildErrors = (rebuilt.diagnostics ?? []).filter(
- (d) => d.severity === DiagnosticSeverity.Error,
- );
+ const rebuilt = await buildDocument(outPath).catch(failInternal);
+ const buildErrors = diagnosticsOf(rebuilt, DiagnosticSeverity.Error);
if (buildErrors.length > 0) {
warn(
`Warning: the printed script draws ${buildErrors.length} error(s) ` +
- 'when built; hand-repair is needed:',
+ 'when built and needs hand-repair:',
);
for (const diag of buildErrors) {
warn(formatDiagnostic(rebuilt, diag));
diff --git a/packages/cli/src/util.ts b/packages/cli/src/util.ts
index 3d67449..4f420ef 100644
--- a/packages/cli/src/util.ts
+++ b/packages/cli/src/util.ts
@@ -5,19 +5,33 @@ import chalk from 'chalk';
import type { LangiumDocument } from 'langium';
import { URI } from 'langium';
import { NodeFileSystem } from 'langium/node';
-import { createBpmnScriptServices, Diagnostic } from '@bpmn-script/language';
+import {
+ createBpmnScriptServices,
+ Diagnostic,
+ DiagnosticSeverity,
+} from '@bpmn-script/language';
export function fail(code: number, message: string): never {
console.error(chalk.red(message));
process.exit(code);
}
+/** Exit 3: an unexpected exception in a transform, as opposed to bad input. */
+export function failInternal(err: unknown): never {
+ fail(3, `Error: internal error (a bug in bpmns): ${(err as Error).message}`);
+}
+
export function warn(message: string): void {
console.error(chalk.yellow(message));
}
+/** Indents a message's note and help lines under its headline. */
+export function indentNotes(message: string): string {
+ return message.replaceAll('\n', '\n ');
+}
+
// One level below the package root in both `out/` and `src/`.
-export const CLI_VERSION: string = (
+export const CLI_VERSION = (
JSON.parse(
readFileSync(new URL('../package.json', import.meta.url), 'utf-8'),
) as { version: string }
@@ -62,7 +76,8 @@ export function guardOutputPath(
if (!opts.force && existsSync(outPath)) {
fail(
2,
- `Error: ${outPath} exists; pass --force to overwrite it or -o for another path`,
+ `Error: ${outPath} exists\n` +
+ " help: pass '--force' to overwrite it, or '-o' for another path",
);
}
}
@@ -96,12 +111,22 @@ export async function buildDocument(
return document;
}
+export function diagnosticsOf(
+ document: LangiumDocument,
+ severity: DiagnosticSeverity,
+): Diagnostic[] {
+ return (document.diagnostics ?? []).filter((d) => d.severity === severity);
+}
+
export function formatDiagnostic(
document: LangiumDocument,
diagnostic: Diagnostic,
): string {
- return (
- ` line ${diagnostic.range.start.line + 1}: ${Diagnostic.getMessageString(diagnostic)}` +
- ` [${document.textDocument.getText(diagnostic.range)}]`
- );
+ const [headline, ...notes] =
+ Diagnostic.getMessageString(diagnostic).split('\n');
+ return [
+ ` line ${diagnostic.range.start.line + 1}: ${headline}` +
+ ` [${document.textDocument.getText(diagnostic.range)}]`,
+ ...notes.map((note) => ` ${note}`),
+ ].join('\n');
}
diff --git a/packages/cli/test/build-parse.smoke.test.ts b/packages/cli/test/build-parse.smoke.test.ts
index f7ac311..95ca518 100644
--- a/packages/cli/test/build-parse.smoke.test.ts
+++ b/packages/cli/test/build-parse.smoke.test.ts
@@ -12,7 +12,6 @@ import type { Model } from '@bpmn-script/language';
import { xmlToIr } from '@bpmn-script/transform';
import {
- expectMentions,
runActionAt,
runBuild,
runParse,
@@ -101,6 +100,12 @@ const TWO_DROPPED_CONDITIONS_BPMN = `
`;
+const dropped = (condition: string, step: string): string =>
+ `Warning: condition '\${${condition}}' on the route out of '${step}' was dropped\n` +
+ ` note: it is the only route out of '${step}', and BPMNscript writes conditions only on the branches of a split\n` +
+ ' note: when the condition is false, Operaton stops the original process with an error\n' +
+ ' note: the rebuilt process always continues';
+
// A number field whose default the engine's `LongFormType` cannot convert:
// imported as written, refused by the validator.
const DECIMAL_DEFAULT_BPMN = `
@@ -122,21 +127,12 @@ const DECIMAL_DEFAULT_BPMN = `
`;
-type ParseExpectation = {
- /** The id of every `Warning: : ...` line, in the order printed. */
- warningIds: string[];
- mentions?: string[];
- script?: string[];
- /** Set where the warnings differ in nothing but the element they name. */
- sameMessage?: boolean;
- /** The re-validation lines after the warnings, whole; a RegExp where the line number is not pinned. */
- buildErrorLines?: (string | RegExp)[];
-};
-
type ParseRow = readonly [
title: string,
input: Input,
- expected: ParseExpectation,
+ /** Every stderr entry, whole. */
+ stderr: string[],
+ script: string,
];
describe('bpmns parse', () => {
@@ -144,74 +140,94 @@ describe('bpmns parse', () => {
[
'a BPMN this tool generated decompiles with nothing to report',
{ file: GOLDEN_GENERATED_BPMN },
- { warningIds: [] },
+ [],
+ `process invoice-approval {
+ start ReviewStart {
+ form {
+ amount: number "Invoice amount"
+ }
+ }
+ user ReviewInvoice(assignee: "demo")
+ if (amount > 1000) {
+ user SeniorApproval(assignee: "manager")
+ } else {
+ service AutoApprove(class: "com.example.invoice.AutoApproveDelegate")
+ }
+ end Done
+}
+`,
],
[
'a region the decompiler cannot phrase is written with a hand-repair marker, and both warnings name the split it starts at',
{ text: UNSTRUCTURED_FORK_BPMN },
- {
- warningIds: ['Fork', 'Fork'],
- mentions: ['unstructured region', 'hand-repair'],
- script: ['// unstructured region: hand-repair required'],
- },
+ [
+ "Warning: gateway 'Fork' was printed as jumps and its split was lost\n" +
+ ' note: the branches leaving it have no form in the script, so a branch leaves as a jump, or as a marker where it opens on something the script cannot name\n' +
+ ' note: a condition weighing a branch is written on its jump\n' +
+ ' note: whether the split opened one branch, every branch whose condition held, or the first to resolve is written nowhere\n' +
+ ' note: a jump ends the path it sits on, so at most one branch is left running\n' +
+ ' note: the marker line above the jumps is where hand-repair starts',
+ "Warning: a route into 'Fork' was left out of the script\n" +
+ ' note: the route has no form in the script, so this part of the script is unstructured\n' +
+ " note: the marker comment where it belonged names 'Fork' and is where hand-repair starts",
+ ],
+ `process unstructured {
+ start S
+ // unstructured region: hand-repair required (split Fork degraded to jumps; was parallel)
+ if (true) {
+ goto A
+ } else {
+ goto B
+ }
+ user A
+ end E
+ user B
+ // unstructured region: hand-repair required (dropped edge into Fork)
+}
+`,
],
[
- 'two steps that lost the same thing are told apart by the id each line leads with',
+ 'two steps that lost the same thing are told apart by the step each headline names',
{ text: TWO_DROPPED_CONDITIONS_BPMN },
- {
- warningIds: ['CheckStock', 'ReserveGoods'],
- sameMessage: true,
- script: ['CheckStock', 'ReserveGoods'],
- },
+ [dropped('inStock', 'CheckStock'), dropped('paid', 'ReserveGoods')],
+ `process two-conditions {
+ var inStock: any
+ var paid: any
+ start Start
+ user CheckStock(label: "Check stock")
+ user ReserveGoods(label: "Reserve goods")
+ user ShipOrder(label: "Ship order")
+ end Done
+}
+`,
],
[
'a setting the import warning names as an eventual failure is confirmed, after that warning, by re-validating the printed script',
{ text: DECIMAL_DEFAULT_BPMN },
- {
- warningIds: ['Review'],
- mentions: ["default '1.5'", 'imported as written'],
- script: ['amount: number = 1.5'],
- buildErrorLines: [
- 'Warning: the printed script draws 1 error(s) when built; hand-repair is needed:',
- /^ {2}line \d+: The default 1\.5 of number field 'amount' is not an integer; the engine converts it with Long\.valueOf every time the form renders \(LongFormType\.convertValue\) and throws on anything else\. \[.+\]$/,
- ],
- },
+ [
+ "Warning: the engine cannot use default '1.5' on form field 'amount' of 'Review' as written\n" +
+ " note: 'LongFormType.convertValue' parses it with 'Long.valueOf' on every render of the form, and it is not an integer\n" +
+ ' note: it was imported as written, and the printed script draws an error at the field',
+ 'Warning: the printed script draws 1 error(s) when built and needs hand-repair:',
+ " line 5: the default 1.5 of number field 'amount' is not an integer [1.5]\n" +
+ ' note: the engine converts it with Long.valueOf every time the form renders and throws on anything else',
+ ],
+ `process decimal-default-carry {
+ start S
+ user Review {
+ form {
+ amount: number = 1.5
+ }
+ }
+ end E
+}
+`,
],
- ])('%s', async (_title, input, expected) => {
+ ])('%s', async (_title, input, stderr, script) => {
const run = await runParse(input);
- expect(run.exit).toBeUndefined();
- expect(run.output).toBeDefined();
-
- const tailLen = expected.buildErrorLines?.length ?? 0;
- expect(run.stderr).toHaveLength(expected.warningIds.length + tailLen);
- const splitAt = run.stderr.length - tailLen;
- const idLines = run.stderr.slice(0, splitAt);
- const tail = run.stderr.slice(splitAt);
-
- const prefixes = idLines.map(
- (line) => /^Warning: ([^:]+): /.exec(line)?.[1],
- );
- expect(prefixes).toEqual(expected.warningIds);
-
- tail.forEach((line, i) => {
- const want = expected.buildErrorLines![i];
- if (want instanceof RegExp) expect(line).toMatch(want);
- else expect(line).toBe(want);
- });
-
- expectMentions(idLines.join('\n'), expected.mentions ?? []);
- expectMentions(run.output ?? '', expected.script ?? []);
-
- if (expected.sameMessage) {
- const bodies = idLines.map((line, i) =>
- line.slice(`Warning: ${expected.warningIds[i]}: `.length),
- );
- expect(new Set(bodies).size).toBe(1);
- expect(bodies[0]).not.toBe('');
- }
-
- const document = await parse(run.output!);
+ expect(run).toEqual({ exit: undefined, stderr, output: script });
+ const document = await parse(script);
expect(document.parseResult.parserErrors).toHaveLength(0);
});
});
@@ -243,17 +259,14 @@ const TYPE_MISMATCH_SOURCE = `process type-mismatch {
}
`;
-type BuildExpectation = {
- exit?: number;
- reimportsAs?: string;
- stderrLines: number;
- mentions?: string[];
-};
-
type BuildRow = readonly [
title: string,
input: Input,
- expected: BuildExpectation,
+ exit: number | undefined,
+ /** Every stderr entry, whole. */
+ stderr: string[],
+ /** The process id the written BPMN imports back as; undefined where nothing is written. */
+ reimportsAs: string | undefined,
];
describe('bpmns build', () => {
@@ -261,44 +274,49 @@ describe('bpmns build', () => {
[
'the invoice-approval example builds to BPMN that imports back under its own id',
{ file: INVOICE_APPROVAL_SRC },
- { reimportsAs: 'invoice-approval', stderrLines: 0 },
+ undefined,
+ [],
+ 'invoice-approval',
],
[
'an undeclared variable is only a warning, so the build still writes its output',
{ text: WARNING_ONLY_SOURCE },
- {
- reimportsAs: 'warning-only',
- stderrLines: 1,
- mentions: ['amount', 'not declared'],
- },
+ undefined,
+ [
+ "Warning: line 3: variable 'amount' is not declared\n" +
+ " help: add 'var amount: ' to the process",
+ ],
+ 'warning-only',
],
[
'a type mismatch fails the build with exit code 1 and writes nothing',
{ text: TYPE_MISMATCH_SOURCE },
- { exit: 1, stderrLines: 2, mentions: ['Validation errors:'] },
+ 1,
+ [
+ 'Validation errors:',
+ " line 4: variable 'amount' of type 'string' cannot be used in an ordered comparison with '>' [amount > 1000]",
+ ],
+ undefined,
],
[
'a keyword typo lists the parser error instead of the no-process message',
{ text: KEYWORD_TYPO_SOURCE },
- {
- exit: 1,
- stderrLines: 2,
- mentions: ['Validation errors:', 'proces'],
- },
+ 1,
+ [
+ 'Validation errors:',
+ " line 1: unexpected 'proces' outside any process [proces]",
+ ],
+ undefined,
],
- ])('%s', async (_title, input, expected) => {
+ ])('%s', async (_title, input, exit, stderr, reimportsAs) => {
const run = await runBuild(input);
- expect(run.exit).toBe(expected.exit);
- expect(run.stderr).toHaveLength(expected.stderrLines);
- expectMentions(run.stderr.join('\n'), expected.mentions ?? []);
-
- if (expected.reimportsAs === undefined) {
+ expect([run.exit, run.stderr]).toEqual([exit, stderr]);
+ if (reimportsAs === undefined) {
expect(run.output).toBeUndefined();
return;
}
- expect(run.output).toBeDefined();
- expect((await xmlToIr(run.output!)).ir.id).toBe(expected.reimportsAs);
+ expect((await xmlToIr(run.output!)).ir.id).toBe(reimportsAs);
expect(run.output!.match(/exporterVersion="[^"]*"/g)).toEqual([
`exporterVersion="${PACKAGE_VERSION}"`,
]);
@@ -323,14 +341,14 @@ const SWAPPED_DSL =
'process rechnung_prüfen { start S user Prüfung(assignee: "demo") end E }';
const NOT_XML = (preview: string) =>
- `Error: not an XML document (starts with "${preview}"); ` +
- 'a .bpmnscript file is built with `bpmns build`';
+ `Error: not an XML document (starts with '${preview}')\n` +
+ " help: build a .bpmnscript file with 'bpmns build'";
type GuardCase = {
inputPath: string;
opts: CommandOptions;
exit: number | undefined;
- /** The first stderr line, where the row expects one. */
+ /** The one stderr entry, where the row expects one. */
line?: string;
check?: () => void;
};
@@ -370,7 +388,9 @@ const refusesExisting =
inputPath,
opts: {},
exit: 2,
- line: `Error: ${outputPath} exists; pass --force to overwrite it or -o for another path`,
+ line:
+ `Error: ${outputPath} exists\n` +
+ " help: pass '--force' to overwrite it, or '-o' for another path",
check: () =>
expect(fs.readFileSync(outputPath, 'utf-8')).toBe('PRE-EXISTING'),
};
@@ -526,8 +546,8 @@ describe('bpmns build / bpmns parse: guards against destructive or unclear failu
'order.txt',
VALID_DSL,
2,
- 'Error: expected a file with one of these extensions: .bpmnscript; ' +
- 'a .bpmn file is decompiled with `bpmns parse`',
+ 'Error: expected a file with one of these extensions: .bpmnscript\n' +
+ " help: decompile a .bpmn file with 'bpmns parse'",
),
refusedFile(
'build: an empty source is reported plainly, without a pipeline stage name',
@@ -577,9 +597,10 @@ describe('bpmns build / bpmns parse: guards against destructive or unclear failu
'hi',
2,
(inputPath) =>
- `Error: failed to parse ${inputPath}: failed to parse document as ` +
- '(root element is ; expected in namespace ' +
- 'http://www.omg.org/spec/BPMN/20100524/MODEL)',
+ `Error: failed to parse ${inputPath}: failed to parse document as \n` +
+ " note: the root element is ''\n" +
+ " note: BPMN expects '' in the namespace " +
+ "'http://www.omg.org/spec/BPMN/20100524/MODEL'",
),
refusedFile(
'parse: a wrong bpmn namespace names the namespace it found',
@@ -590,9 +611,11 @@ describe('bpmns build / bpmns parse: guards against destructive or unclear failu
'',
2,
(inputPath) =>
- `Error: failed to parse ${inputPath}: failed to parse document as ` +
- '(root element is ; expected in namespace ' +
- 'http://www.omg.org/spec/BPMN/20100524/MODEL; found xmlns:bpmn=http://example.com/wrong)',
+ `Error: failed to parse ${inputPath}: failed to parse document as \n` +
+ " note: the root element is ''\n" +
+ " note: BPMN expects '' in the namespace " +
+ "'http://www.omg.org/spec/BPMN/20100524/MODEL'\n" +
+ " note: the file declares 'xmlns:bpmn=http://example.com/wrong'",
),
refusedFile(
'parse: an unclosed tag with no closing bracket anywhere is cut to its first line, capped at 200 characters, with any control byte stripped',
@@ -612,7 +635,7 @@ describe('bpmns build / bpmns parse: guards against destructive or unclear failu
const { inputPath, opts, exit, line, check } = make(dir);
const run = await runActionAt(action, inputPath, opts);
expect(run.exit).toBe(exit);
- if (line !== undefined) expect(run.stderr[0]).toBe(line);
+ expect(run.stderr).toEqual(line === undefined ? [] : [line]);
check?.();
} finally {
await fsp.rm(dir, { recursive: true, force: true });
diff --git a/packages/cli/test/build.layout-guard.test.ts b/packages/cli/test/build.layout-guard.test.ts
index 37815a2..50a9861 100644
--- a/packages/cli/test/build.layout-guard.test.ts
+++ b/packages/cli/test/build.layout-guard.test.ts
@@ -15,9 +15,9 @@ describe('bpmns build: layoutProcess guard', () => {
expect(run.exit).toBeUndefined();
expect(run.stderr).toEqual([
- 'Warning: no diagram could be drawn for this process (bpmn-auto-layout ' +
- 'failed to lay out the process: Cannot set properties of undefined); ' +
- 'the file deploys but opens without shapes in a modeler',
+ 'Warning: no diagram could be drawn for this process\n' +
+ " note: 'bpmn-auto-layout' failed to lay out the process: Cannot set properties of undefined\n" +
+ ' note: the file deploys, but opens without shapes in a modeler',
]);
expect(run.output).toBeDefined();
expect(run.output).not.toContain('bpmndi:');
diff --git a/packages/cli/test/decompile-contract.e2e.test.ts b/packages/cli/test/decompile-contract.e2e.test.ts
index 4581332..1d1444c 100644
--- a/packages/cli/test/decompile-contract.e2e.test.ts
+++ b/packages/cli/test/decompile-contract.e2e.test.ts
@@ -17,7 +17,7 @@ import {
UnsupportedEventFeatureError,
} from '@bpmn-script/transform';
-import { runBuild, runParse, expectMentions } from './helpers/actions.js';
+import { runBuild, runParse } from './helpers/actions.js';
const REPO_ROOT = fileURLToPath(new URL('../../..', import.meta.url));
@@ -87,19 +87,23 @@ describe('decompile contract on the fixtures', () => {
]);
const parsed = await runParse({ file: LANES_AND_ASYNC_BPMN });
- expect(parsed.exit).toBeUndefined();
- expect(
- parsed.stderr.map((line) => /^Warning: ([^:]+): /.exec(line)?.[1]),
- ).toEqual(['Lane_Ops', 'ReviewRequest']);
- expectMentions(parsed.stderr.join('\n'), ['operaton:properties']);
+ expect(parsed).toEqual({
+ exit: undefined,
+ stderr: [
+ "Warning: lane 'Operations' (Lane_Ops) was not imported\n" +
+ ' note: every step is placed in a single flat process',
+ "Warning: 'operaton:properties' on 'ReviewRequest' was not imported\n" +
+ " note: BPMNscript reads no such setting on a 'bpmn:userTask'\n" +
+ ' note: the rebuilt document carries none',
+ ],
+ output: `process lanes-and-async {
+ start ReviewStart
+ user ReviewRequest(label: "Review request", assignee: "demo", asyncBefore: true)
+ end ReviewDone
+}
+`,
+ });
const dsl = parsed.output!;
- expectMentions(dsl, [
- 'process lanes-and-async',
- 'start ReviewStart',
- 'user ReviewRequest',
- 'assignee: "demo"',
- 'end ReviewDone',
- ]);
const { document, diagnostics } = await validate(dsl);
expect(document.parseResult.parserErrors).toHaveLength(0);
@@ -122,11 +126,16 @@ describe('decompile contract on the fixtures', () => {
// 1 means unsupported construct; 2 would mean I/O or generic failure.
const run = await runParse({ file: ERROR_START_BPMN });
- expect(run.exit).toBe(1);
- expect(run.output).toBeUndefined();
- const stderr = run.stderr.join('\n');
- expectMentions(stderr, ['ShipmentFailed', "Catch it with 'on error'"]);
- assertNoForbiddenJargon(stderr);
+ expect(run).toEqual({
+ exit: 1,
+ stderr: [
+ `Error: ${ERROR_START_BPMN}: element 'ShipmentFailed' cannot be imported: a process cannot start on an error\n` +
+ ' note: Operaton ignores the trigger and starts the process as if none were written\n' +
+ ' note: importing it would write back a document the engine runs differently from what it says\n' +
+ " help: catch it with 'on error' inside the scope that raises it",
+ ],
+ output: undefined,
+ });
});
});
@@ -139,51 +148,52 @@ describe('decompile contract: the script it hands back goes through the pipeline
"a modelling tool's default ids keep their statements and labels",
'StartEvent_1',
'EndEvent_1',
- [
- 'start StartEvent_1(label: "Order received")',
- 'end EndEvent_1(label: "Order filed")',
- ],
+ `process generated-id-labels {
+ start StartEvent_1(label: "Order received")
+ user Approve
+ end EndEvent_1(label: "Order filed")
+}
+`,
+ [],
[],
- 0,
],
[
'the start id this tool generates for the process drops its statement and label, but a like-named end keeps both and is refused on the name alone',
'StartEvent_generated-id-labels',
'EndEvent_generated-id-labels',
- ['end EndEvent_generated-id-labels(label: "Order filed")'],
- ['StartEvent_generated-id-labels'],
- 1,
+ `process generated-id-labels {
+ user Approve
+ end EndEvent_generated-id-labels(label: "Order filed")
+}
+`,
+ [
+ "label 'Order received' on 'StartEvent_generated-id-labels' was not written to the script\n" +
+ "note: 'StartEvent_generated-id-labels' is the kind of name BPMNscript generates for itself, which a script cannot repeat\n" +
+ 'note: this start is left out entirely, and its label with it\n' +
+ 'help: rename it in the diagram to keep the label',
+ ],
+ [
+ "statement name 'EndEvent_generated-id-labels' is the id generated for the implicit end event of 'generated-id-labels'\n" +
+ 'help: choose another name',
+ ],
],
])(
'the DSL produced from a diagram where %s',
- async (
- _title,
- startId,
- endId,
- printedLines,
- warnedIds,
- diagnosticCount,
- ) => {
+ async (_title, startId, endId, printed, labelWarnings, errors) => {
const { ir, warnings } = await xmlToIr(
labeledTerminalsBpmn(startId, endId),
);
const dsl = irToDsl(ir).source;
+ expect(dsl).toBe(printed);
+ expect(
+ warnings.filter((w) => w.category === 'label').map((w) => w.message),
+ ).toEqual(labelWarnings);
const { document, diagnostics } = await validate(dsl);
expect(document.parseResult.parserErrors).toHaveLength(0);
- expect(diagnostics).toHaveLength(diagnosticCount);
expect(
- dsl.split('\n').filter((line) => /^\s+(start|end) /.test(line)),
- ).toEqual(printedLines.map((line) => ` ${line}`));
-
- const labelWarnings = warnings.filter((w) => w.category === 'label');
- expect(labelWarnings.map((w) => w.elementId)).toEqual(warnedIds);
- for (const w of labelWarnings) {
- expect(w.message).toContain(
- w.elementId === startId ? 'Order received' : 'Order filed',
- );
- assertNoForbiddenJargon(w.message);
- }
+ diagnostics.map((d) => [d.severity, Diagnostic.getMessageString(d)]),
+ ).toEqual(errors.map((message) => [1, message]));
},
);
});
@@ -215,7 +225,8 @@ process Second {
diagnostics.map((d) => Diagnostic.getMessageString(d)).sort(),
).toEqual(
[
- 'Only one process is supported per file. Move additional processes into separate files.',
+ 'only one process is supported per file\n' +
+ 'help: move additional processes into separate files',
intoBranchMessage('goto A', 'goto', 'parallel'),
].sort(),
);
diff --git a/packages/cli/test/helpers/actions.ts b/packages/cli/test/helpers/actions.ts
index 51ef165..dbe4d3e 100644
--- a/packages/cli/test/helpers/actions.ts
+++ b/packages/cli/test/helpers/actions.ts
@@ -3,7 +3,7 @@ import * as fsp from 'node:fs/promises';
import * as os from 'node:os';
import * as path from 'node:path';
import chalk from 'chalk';
-import { expect, vi } from 'vitest';
+import { vi } from 'vitest';
import { buildAction } from '../../src/build.js';
import { parseAction } from '../../src/parse.js';
@@ -106,14 +106,3 @@ export const runBuild = (input: Input): Promise =>
export const runParse = (input: Input): Promise =>
run(parseAction, '.bpmn', '.bpmnscript', input);
-
-export function expectMentions(
- text: string,
- mentions: readonly string[],
-): void {
- for (const mention of mentions) {
- expect(text, `expected to find "${mention}" in: ${text}`).toContain(
- mention,
- );
- }
-}
diff --git a/packages/cli/test/internal-failure.test.ts b/packages/cli/test/internal-failure.test.ts
new file mode 100644
index 0000000..867ceba
--- /dev/null
+++ b/packages/cli/test/internal-failure.test.ts
@@ -0,0 +1,46 @@
+// Its own file because `vi.mock` applies to the whole file.
+import { describe, it, expect, vi } from 'vitest';
+
+vi.mock('@bpmn-script/transform', async (importOriginal) => ({
+ ...(await importOriginal()),
+ irToXml: vi.fn(() => {
+ throw new Error('boom in irToXml');
+ }),
+ irToDsl: vi.fn(() => {
+ throw new Error('boom in irToDsl');
+ }),
+}));
+
+import { runBuild, runParse } from './helpers/actions.js';
+
+const BPMN = `
+
+
+
+
+
+
+`;
+
+describe('an exception inside a transform', () => {
+ it.each([
+ [
+ 'build exits 3 and writes nothing',
+ () => runBuild({ text: 'process p { start S end E }' }),
+ 'boom in irToXml',
+ ],
+ [
+ 'parse exits 3 and writes nothing',
+ () => runParse({ text: BPMN }),
+ 'boom in irToDsl',
+ ],
+ ])('%s', async (_title, go, boom) => {
+ const run = await go();
+
+ expect(run.exit).toBe(3);
+ expect(run.stderr).toEqual([
+ `Error: internal error (a bug in bpmns): ${boom}`,
+ ]);
+ expect(run.output).toBeUndefined();
+ });
+});
diff --git a/packages/extension/README.md b/packages/extension/README.md
index aba0fe4..0daade5 100644
--- a/packages/extension/README.md
+++ b/packages/extension/README.md
@@ -1,70 +1,76 @@
# vscode-bpmnscript
The VS Code extension for BPMNscript.
-It runs the Langium language server for highlighting, completion, hover, go to definition, references, rename, the outline and inline diagnostics, and it converts the open file between `.bpmnscript` and `.bpmn` from a sidebar panel or the command palette.
+It runs the language server for highlighting, completion, hover, go to definition, references, rename, the outline and inline diagnostics, and it converts the open file between `.bpmnscript` and `.bpmn` from a sidebar panel or the command palette.
-The language intelligence itself lives in `@bpmn-script/language`; this package loads it in VS Code.
-That wiring is mostly Langium scaffold, which is the point of choosing Langium in the first place ([ADR-0003](https://github.com/BPMNscript/bpmnscript/blob/main/docs/decisions/0003-use-langium-as-language-workbench.md)).
-The conversion layer on top is project-specific: three commands (`bpmnscript.compile`, `bpmnscript.decompile`, and `bpmnscript.openAndDecompile`, which picks a BPMN file from disk and decompiles it) and a sidebar webview that drives them for the active file.
+The language intelligence lives in `@bpmn-script/language`, and this package loads it into VS Code.
+That wiring is mostly Langium scaffold ([ADR-0003](https://github.com/BPMNscript/bpmnscript/blob/main/docs/decisions/0003-use-langium-as-language-workbench.md)).
+What is specific to this project is the conversion layer: three commands (`bpmnscript.compile`, `bpmnscript.decompile`, and `bpmnscript.openAndDecompile`, which picks a BPMN file from disk and decompiles it) and a sidebar webview that drives them.
-## How it fits together
+## Installing
-Three parts, two bundles: the client and the conversion layer in `out/extension/main.cjs`, the language server in `out/language/main.cjs`.
+```bash
+npm run build
+npm run package -w packages/extension
+code --install-extension packages/extension/vscode-bpmnscript-0.1.0.vsix
+```
-The extension client (`src/extension/main.ts`) runs inside VS Code.
-Opening a `.bpmnscript` file starts the language server and connects to it; the client also registers the conversion commands, wires up the sidebar webview provider, and listens for editor changes to keep the sidebar in sync.
+VS Code then shows the BPMNscript icon in the activity bar and offers `BPMNscript: Compile to BPMN` in the command palette when a `.bpmnscript` file is open.
-The language server (`src/language/main.ts`) runs in a background process.
-It imports `createBpmnScriptServices` from `@bpmn-script/language` and answers the editor's LSP requests.
-Hover shows a step's kind and label, a code's kind and message, a variable's type, and a `/** ... */` comment written before the statement.
-Completion offers only what the validator accepts at that position, never a fixed keyword list.
-Rename edits every site of a step, a code or a variable, or refuses when the caret isn't on one.
+To try a change to the extension without packaging it, press F5 in VS Code from the repo root.
+A second window opens with the extension loaded.
+
+## How it fits together
+
+The extension has three parts in two bundles: the client and the conversion layer in `out/extension/main.cjs`, and the language server in `out/language/main.cjs`.
-The conversion layer splits along the VS Code boundary.
-`conversion-core.ts` is a pure, `vscode`-free module driving the `compileDslToBpmn` and `decompileBpmnToDsl` pipelines, and it holds the decisions: severity gating (warnings don't block a compile), error classification, unsupported-element handling.
-A successful decompile also returns `warnings`, what `xmlToIr` reported on the way in and `irToDsl` on the way out, in one list.
-Because nothing here touches `vscode`, it's testable under vitest with no editor host.
-`conversion.ts` is the adapter around it: it resolves the source URI (an argument, otherwise the active editor), refuses a file whose extension is not the one the command takes and names the command that is, reads the text (preferring an unsaved in-memory document), calls the core, opens the Problems panel on a validation failure (the language server already publishes the same diagnostics), asks before overwriting an existing output file, writes the result next to the source with the extension swapped, and opens it.
-A BPMN construct the transform refuses surfaces as an error notification and no file is written; any `warnings` surface as one aggregated notification listing what the two hops reported.
+The client (`src/extension/main.ts`) runs inside VS Code.
+It starts the language server when a `.bpmnscript` file opens, registers the conversion commands and the sidebar, and keeps the sidebar in sync with the active editor.
-`sidebar-view-provider.ts` implements `WebviewViewProvider` for the "Convert" view in the "BPMNscript" activity-bar container.
-The webview (`media/sidebar.{html,css,js}`) posts `{type:'compile'|'decompile'|'open'|'pick', uri}` messages that the provider dispatches to those same commands, so the sidebar and the palette behave identically.
-It follows the active editor, showing the current file, one convert button, and a link to the counterpart file when that already exists on disk.
-Conversions open their output, so moving between the two files is one click.
+The language server (`src/language/main.ts`) runs in a separate process.
+It loads `createBpmnScriptServices` from `@bpmn-script/language` and answers the editor's LSP requests.
+Hover shows a step's kind and label, a code's kind and message, a variable's type, and a `/** ... */` comment written before the statement.
+Completion offers only what the validator accepts at that position.
+Rename edits every site of a step, a code or a variable.
+
+The conversion layer is split along the VS Code boundary.
+`conversion-core.ts` has no `vscode` import, so vitest tests it without an editor host.
+It runs the compile and decompile pipelines and decides what blocks a conversion: errors do, warnings don't.
+A decompile returns the warnings from both `xmlToIr` and `irToDsl` in one list.
+`conversion.ts` is the VS Code adapter around it, and it behaves as follows:
+
+- The source is the command's argument, otherwise the active editor, and an unsaved editor's text is used as it stands.
+- A file with the wrong extension for the command is refused, and the message names the command that takes it.
+- A validation failure opens the Problems panel, where the language server already shows the diagnostics.
+- The output goes next to the source with the extension swapped; an existing file is overwritten only after you confirm, and the output opens when written.
+- A compile whose diagram can't be drawn still writes the file and shows a warning.
+- A BPMN construct the transform refuses shows an error notification with its headline, and nothing is written.
+- Warnings show as one notification giving their count.
+ Its Show Details button opens the BPMNscript output channel, which holds the full messages with their `note:` and `help:` lines.
+
+`sidebar-view-provider.ts` provides the "Convert" view in the "BPMNscript" activity-bar container.
+The webview (`media/sidebar.{html,css,js}`) shows the active file, one convert button, and a link to the counterpart file when it exists on disk.
+Its buttons post messages that the provider dispatches to the same commands as the palette, so both behave identically.
## Syntax highlighting
-The base TextMate grammar is generated from the `language` package's `.langium` grammar at build time and copied in, so it always tracks the real grammar.
-`packages/language/textmate-postprocess.mjs` adjusts it right after generation, so a hyphenated name keeps its color instead of losing it at the first `-`, and so numbers and operators get a scope the generator leaves out.
+The base TextMate grammar is generated from the `language` package's Langium grammar at build time and copied in, so it always tracks the real grammar.
+`packages/language/textmate-postprocess.mjs` adjusts it after generation, so a hyphenated name keeps its color past the first `-`, and numbers and operators get a scope.
-A second, hand-maintained TextMate injection grammar (`injection/bpmn-script.injection.tmLanguage.json`) colors the body of a `script` task the way a markdown fenced code block works: the opening language tag selects the embedded scope (`source.js`, `source.python`, `source.ruby`, `source.groovy`), and `feel` or any other accepted tag without an installed grammar falls back to a plain uncolored block.
-This is highlighting only, with no autocomplete, hover, or diagnostics inside the fence.
-`build:prepare` copies the injection asset into `syntaxes/` next to the base grammar, and `package.json`'s `contributes.grammars` registers it with `injectTo: ["source.bpmn-script"]`.
+A hand-maintained injection grammar (`injection/bpmn-script.injection.tmLanguage.json`) colors the body of a `script` task the way a Markdown fenced code block works.
+The opening tag selects the embedded scope (`source.js`, `source.python`, `source.ruby`, `source.groovy`); `feel` and any other accepted tag without an installed grammar stay uncolored.
+Inside the fence there is highlighting only, with no completion, hover, or diagnostics.
+`build:prepare` copies the injection grammar into `syntaxes/`, and `contributes.grammars` in `package.json` registers it with `injectTo: ["source.bpmn-script"]`.
-## Build and run
+## Build
```bash
# From repo root
npm run build --workspace packages/extension
```
-`esbuild` bundles both entry points into CommonJS under `out/`, which is how VS Code loads extensions.
-To try it live, press F5 in VS Code from the repo root: a second window opens with the extension loaded, where `.bpmnscript` files get language support and `.bpmn` files get the decompile command and the sidebar panel.
-See [CONTRIBUTING.md](https://github.com/BPMNscript/bpmnscript/blob/main/CONTRIBUTING.md#trying-it-out-in-vs-code).
-
-Build order matters.
-The extension bundles `@bpmn-script/language` and `@bpmn-script/transform` from their compiled `out/` directories, so a source edit in either one is invisible until you rebuild it (or run `npm run build` from the repo root).
-
-## Installing
-
-```bash
-npm run build
-npm run package -w packages/extension
-code --install-extension packages/extension/vscode-bpmnscript-0.0.1.vsix
-```
-
-VS Code then shows the BPMNscript icon in the activity bar and offers `BPMNscript: Compile to BPMN` in the command palette when a `.bpmnscript` file is open.
-F5 from the repo root stays the way to try a change to the extension itself without packaging it.
+`esbuild` bundles both entry points into CommonJS under `out/`.
+The bundle takes `@bpmn-script/language` and `@bpmn-script/transform` from their compiled `out/` directories, so a source change in either is invisible until you rebuild it, or run `npm run build` from the repo root.
## Source layout
@@ -85,4 +91,4 @@ F5 from the repo root stays the way to try a change to the extension itself with
| `esbuild.mjs` | Bundles both entry points; adds the `import.meta.url` CJS shim and copies the moddle asset |
| `injection/bpmn-script.injection.tmLanguage.json` | Injection grammar for embedded-language highlighting inside a `script` body |
| `syntaxes/` | TextMate grammars, both copied in at build time: the base grammar from `language` and the injection grammar from `injection/` |
-| `LICENSE`, `CHANGELOG.md` | Copied from the repo root by `build:prepare`, git-ignored, packed into the vsix |
+| `LICENSE` | Copied from the repo root by `build:prepare`, git-ignored, packed into the vsix |
diff --git a/packages/extension/language-configuration.json b/packages/extension/language-configuration.json
index c66e306..8e7ed8a 100644
--- a/packages/extension/language-configuration.json
+++ b/packages/extension/language-configuration.json
@@ -5,8 +5,9 @@
// block comment markers
"blockComment": ["/*", "*/"]
},
- // the ID terminal in bpmn-script.langium, so a hyphenated name selects whole
- "wordPattern": "[_a-zA-Z]\\w*(-\\w+)*",
+ // the QUOTED_NAME and ID terminals in bpmn-script.langium, so a hyphenated
+ // name and a name in backticks select whole
+ "wordPattern": "`(\\\\.|[^`\\\\\\r\\n])+`|[_a-zA-Z]\\w*(-\\w+)*",
// symbols used as brackets
"brackets": [
["{", "}"],
diff --git a/packages/extension/package.json b/packages/extension/package.json
index 3131c43..71b18c1 100644
--- a/packages/extension/package.json
+++ b/packages/extension/package.json
@@ -1,7 +1,7 @@
{
"name": "vscode-bpmnscript",
"description": "VS Code extension for BPMNscript, bundling the Langium language server",
- "version": "0.0.1",
+ "version": "0.1.0",
"displayName": "BPMNscript",
"publisher": "bpmnscript",
"license": "Apache-2.0",
@@ -101,9 +101,9 @@
},
"main": "./out/extension/main.cjs",
"scripts": {
- "clean": "shx rm -fr *.tsbuildinfo out syntaxes",
+ "clean": "node -e \"for (const f of [...fs.globSync('*.tsbuildinfo'), 'out', 'syntaxes']) fs.rmSync(f, { recursive: true, force: true })\"",
"vscode:prepublish": "npm run build",
- "build:prepare": "shx mkdir -p ./syntaxes/ && shx cp -f ../language/syntaxes/bpmn-script.tmLanguage.json ./syntaxes/bpmn-script.tmLanguage.json && shx cp -f ./injection/bpmn-script.injection.tmLanguage.json ./syntaxes/bpmn-script.injection.tmLanguage.json && shx cp -f ../../LICENSE ./LICENSE && shx cp -f ../../CHANGELOG.md ./CHANGELOG.md",
+ "build:prepare": "node -e \"fs.cpSync('../language/syntaxes/bpmn-script.tmLanguage.json', 'syntaxes/bpmn-script.tmLanguage.json'); fs.cpSync('injection/bpmn-script.injection.tmLanguage.json', 'syntaxes/bpmn-script.injection.tmLanguage.json'); fs.cpSync('../../LICENSE', 'LICENSE')\"",
"build": "npm run build:prepare && tsc -b tsconfig.json && node esbuild.mjs",
"build:post": "npm run build:prepare && node esbuild.mjs",
"build:clean": "npm run clean && npm run build",
@@ -113,16 +113,17 @@
"package": "vsce package"
},
"dependencies": {
- "@bpmn-script/language": "0.0.1",
- "@bpmn-script/transform": "0.0.1",
- "vscode-languageclient": "~10.1.1"
+ "@bpmn-script/language": "0.1.0",
+ "@bpmn-script/transform": "0.1.0",
+ "langium": "^4.4.0",
+ "vscode-languageclient": "~10.1.2"
},
"devDependencies": {
"@types/vscode": "~1.134.0",
"@vscode/vsce": "^4.0.0",
- "concurrently": "^10.0.5",
+ "concurrently": "^10.0.6",
"esbuild": "~0.28.2",
- "vitest": "^4.1.11"
+ "vitest": "^5.0.5"
},
"vsce": {
"dependencies": false
diff --git a/packages/extension/src/extension/conversion-core.ts b/packages/extension/src/extension/conversion-core.ts
index fdd2c0c..cd8e980 100644
--- a/packages/extension/src/extension/conversion-core.ts
+++ b/packages/extension/src/extension/conversion-core.ts
@@ -7,6 +7,7 @@ import {
} from '@bpmn-script/language';
import type { Model } from '@bpmn-script/language';
import { EmptyFileSystem, URI } from 'langium';
+import type { LangiumDocument } from 'langium';
import * as path from 'node:path';
import {
astToIr,
@@ -37,7 +38,13 @@ export type CompileResult =
| { ok: false; kind: 'error'; message: string };
export type DecompileResult =
- | { ok: true; output: string; warnings: (ImportWarning | PrintWarning)[] }
+ | {
+ ok: true;
+ output: string;
+ warnings: (ImportWarning | PrintWarning)[];
+ /** Errors the printed script draws when compiled; it is still returned. */
+ buildErrors: ConvDiagnostic[];
+ }
| { ok: false; kind: 'unsupported'; message: string }
| { ok: false; kind: 'error'; message: string };
@@ -45,10 +52,10 @@ const { shared } = createBpmnScriptServices(EmptyFileSystem);
let nextDocId = 0;
-export async function compileDslToBpmn(
+async function withBuiltDocument(
source: string,
- exporterVersion: string,
-): Promise {
+ use: (doc: LangiumDocument) => T | Promise,
+): Promise {
const uri = URI.parse(`memory:///conv-${nextDocId++}.bpmnscript`);
// Registered so cross-references resolve, removed so the index does not grow.
@@ -60,69 +67,72 @@ export async function compileDslToBpmn(
try {
await shared.workspace.DocumentBuilder.build([doc], { validation: true });
+ return await use(doc);
+ } finally {
+ shared.workspace.LangiumDocuments.deleteDocument(uri);
+ }
+}
- const errors = (doc.diagnostics ?? []).filter(
- (d) => d.severity === DiagnosticSeverity.Error,
- );
- if (errors.length > 0) {
- const diagnostics: ConvDiagnostic[] = errors.map((d) => ({
- line: d.range.start.line,
- character: d.range.start.character,
- endLine: d.range.end.line,
- endCharacter: d.range.end.character,
- message: Diagnostic.getMessageString(d),
- severity: DiagnosticSeverity.Error,
- text: doc.textDocument.getText(d.range),
- }));
- return { ok: false, kind: 'validation', diagnostics };
- }
+function errorDiagnostics(doc: LangiumDocument): ConvDiagnostic[] {
+ return (doc.diagnostics ?? [])
+ .filter((d) => d.severity === DiagnosticSeverity.Error)
+ .map((d) => ({
+ line: d.range.start.line,
+ character: d.range.start.character,
+ endLine: d.range.end.line,
+ endCharacter: d.range.end.character,
+ message: Diagnostic.getMessageString(d),
+ severity: DiagnosticSeverity.Error,
+ text: doc.textDocument.getText(d.range),
+ }));
+}
- // After the error gate: a keyword typo also parses into a model with no processes.
- if (doc.parseResult.value.processes.length === 0) {
- return { ok: false, kind: 'error', message: NO_PROCESS_MESSAGE };
- }
+export async function compileDslToBpmn(
+ source: string,
+ exporterVersion: string,
+): Promise {
+ try {
+ return await withBuiltDocument(source, async (doc) => {
+ const diagnostics = errorDiagnostics(doc);
+ if (diagnostics.length > 0) {
+ return { ok: false, kind: 'validation', diagnostics };
+ }
- let ir;
- try {
- ir = astToIr(doc.parseResult.value);
- } catch (err) {
- return {
- ok: false,
- kind: 'error',
- message: `AST to IR conversion failed: ${(err as Error).message}`,
- };
- }
+ // After the error gate: a keyword typo also parses into a model with no processes.
+ if (doc.parseResult.value.processes.length === 0) {
+ return { ok: false, kind: 'error', message: NO_PROCESS_MESSAGE };
+ }
- let output;
- let layoutWarning: string | undefined;
- try {
- output = await irToXml(ir, { exporterVersion });
- } catch (err) {
- if (err instanceof LayoutError) {
- output = err.xml;
- layoutWarning = err.message;
- } else {
+ let ir;
+ try {
+ ir = astToIr(doc.parseResult.value);
+ } catch (err) {
return {
ok: false,
kind: 'error',
- message: `IR to XML conversion failed: ${(err as Error).message}`,
+ message: `AST to IR conversion failed: ${(err as Error).message}`,
};
}
- }
- return {
- ok: true,
- output,
- ...(layoutWarning !== undefined ? { layoutWarning } : {}),
- };
+ try {
+ return { ok: true, output: await irToXml(ir, { exporterVersion }) };
+ } catch (err) {
+ if (err instanceof LayoutError) {
+ return { ok: true, output: err.xml, layoutWarning: err.message };
+ }
+ return {
+ ok: false,
+ kind: 'error',
+ message: `IR to XML conversion failed: ${(err as Error).message}`,
+ };
+ }
+ });
} catch (err) {
return {
ok: false,
kind: 'error',
message: (err as Error).message,
};
- } finally {
- shared.workspace.LangiumDocuments.deleteDocument(uri);
}
}
@@ -162,7 +172,20 @@ export async function decompileBpmnToDsl(
};
}
- return { ok: true, output, warnings: [...warnings, ...printWarnings] };
+ // Nothing above runs the validator, so building the script is what catches an error.
+ let buildErrors: ConvDiagnostic[];
+ try {
+ buildErrors = await withBuiltDocument(output, errorDiagnostics);
+ } catch (err) {
+ return { ok: false, kind: 'error', message: (err as Error).message };
+ }
+
+ return {
+ ok: true,
+ output,
+ warnings: [...warnings, ...printWarnings],
+ buildErrors,
+ };
}
// Importing the cli's `resolveOutputPath` would pull chalk and commander into the bundle.
diff --git a/packages/extension/src/extension/conversion.ts b/packages/extension/src/extension/conversion.ts
index 64d6710..559c296 100644
--- a/packages/extension/src/extension/conversion.ts
+++ b/packages/extension/src/extension/conversion.ts
@@ -8,6 +8,29 @@ import {
type ConvertHandler = (uri?: vscode.Uri) => Promise;
+const SHOW_DETAILS = 'Show Details';
+
+let output: vscode.OutputChannel | undefined;
+
+/**
+ * A notification renders its text on one line, so a message's note and help
+ * lines go to the output channel, and the notification offers to open it.
+ */
+function notifyWithDetails(
+ show: typeof vscode.window.showWarningMessage,
+ summary: string,
+ details: readonly string[],
+): void {
+ output ??= vscode.window.createOutputChannel('BPMNscript');
+ output.appendLine(summary);
+ for (const detail of details) {
+ output.appendLine(` ${detail.replaceAll('\n', '\n ')}`);
+ }
+ void Promise.resolve(show(summary, SHOW_DETAILS)).then((choice) => {
+ if (choice === SHOW_DETAILS) output?.show(true);
+ });
+}
+
interface Source {
uri: vscode.Uri;
name: string;
@@ -41,7 +64,7 @@ async function readSource(
const name = path.basename(sourceUri.fsPath);
if (path.extname(sourceUri.fsPath).toLowerCase() !== ext) {
await vscode.window.showWarningMessage(
- `BPMNscript: "${name}" is not a ${ext} file; use "${otherCommand}" for it.`,
+ `BPMNscript: "${name}" is not a ${ext} file. Use "${otherCommand}" for it.`,
);
return undefined;
}
@@ -66,7 +89,7 @@ async function writeOutput(
source: Source,
ext: '.bpmn' | '.bpmnscript',
verb: 'Compiled' | 'Decompiled',
- output: string,
+ content: string,
): Promise {
const outputPath = swapExtension(source.uri.fsPath, ext);
const outputUri = vscode.Uri.file(outputPath);
@@ -75,7 +98,7 @@ async function writeOutput(
}
await vscode.workspace.fs.writeFile(
outputUri,
- new TextEncoder().encode(output),
+ new TextEncoder().encode(content),
);
await vscode.window.showTextDocument(outputUri);
void vscode.window.showInformationMessage(
@@ -136,11 +159,16 @@ export function decompileCommand(): ConvertHandler {
const result = await decompileBpmnToDsl(source.text);
if (!result.ok) {
- await vscode.window.showErrorMessage(
+ const [headline, ...notes] = result.message.split('\n');
+ const summary =
result.kind === 'unsupported'
- ? `BPMNscript: "${source.name}" contains an unsupported construct: ${result.message}`
- : `BPMNscript: Failed to decompile "${source.name}": ${result.message}`,
- );
+ ? `BPMNscript: "${source.name}" cannot be decompiled: ${headline}`
+ : `BPMNscript: Failed to decompile "${source.name}": ${headline}`;
+ if (notes.length === 0) {
+ await vscode.window.showErrorMessage(summary);
+ } else {
+ notifyWithDetails(vscode.window.showErrorMessage, summary, notes);
+ }
return undefined;
}
@@ -151,12 +179,17 @@ export function decompileCommand(): ConvertHandler {
result.output,
);
if (outputUri && result.warnings.length > 0) {
- // Several messages do not name their step, so the id tells them apart.
- const details = result.warnings
- .map((w) => `${w.elementId}: ${w.message}`)
- .join('; ');
- void vscode.window.showWarningMessage(
- `BPMNscript: "${source.name}" reported ${result.warnings.length} item(s) during decompile: ${details}`,
+ notifyWithDetails(
+ vscode.window.showWarningMessage,
+ `BPMNscript: "${source.name}" reported ${result.warnings.length} item(s) during decompile.`,
+ result.warnings.map((w) => w.message),
+ );
+ }
+ if (outputUri && result.buildErrors.length > 0) {
+ notifyWithDetails(
+ vscode.window.showWarningMessage,
+ `BPMNscript: The script decompiled from "${source.name}" has ${result.buildErrors.length} compilation error(s) and needs hand-repair.`,
+ result.buildErrors.map((e) => `line ${e.line + 1}: ${e.message}`),
);
}
return outputUri;
diff --git a/packages/extension/src/extension/main.ts b/packages/extension/src/extension/main.ts
index f313bfa..0a845da 100644
--- a/packages/extension/src/extension/main.ts
+++ b/packages/extension/src/extension/main.ts
@@ -12,13 +12,13 @@ import {
} from './conversion.js';
import { SidebarViewProvider } from './sidebar-view-provider.js';
-let client: LanguageClient;
+let client: LanguageClient | undefined;
export async function activate(
context: vscode.ExtensionContext,
): Promise {
const extensionVersion = String(
- (context.extension.packageJSON as { version?: string }).version ?? '0.0.1',
+ (context.extension.packageJSON as { version?: string }).version,
);
const decompile = decompileCommand();
@@ -47,17 +47,11 @@ export async function activate(
vscode.window.onDidChangeActiveTextEditor(() => void provider.refresh()),
);
- // refresh() no-ops until the view exists.
- void provider.refresh();
-
client = await startLanguageClient(context);
}
export function deactivate(): Promise | undefined {
- if (client) {
- return client.stop();
- }
- return undefined;
+ return client?.stop();
}
async function startLanguageClient(
diff --git a/packages/extension/src/extension/sidebar-view-provider.ts b/packages/extension/src/extension/sidebar-view-provider.ts
index a2319ec..f23bb11 100644
--- a/packages/extension/src/extension/sidebar-view-provider.ts
+++ b/packages/extension/src/extension/sidebar-view-provider.ts
@@ -52,32 +52,19 @@ export class SidebarViewProvider implements vscode.WebviewViewProvider {
});
}
- async refresh(): Promise {
- if (!this._view) return;
- await this._postState();
- }
-
private async _handleMessage(message: unknown): Promise {
const msg = message as { type: string; uri?: string };
switch (msg.type) {
case 'ready':
- await this._postState();
+ await this.refresh();
break;
case 'compile':
- if (msg.uri) {
- await vscode.commands.executeCommand(
- 'bpmnscript.compile',
- vscode.Uri.parse(msg.uri),
- );
- }
- break;
-
case 'decompile':
if (msg.uri) {
await vscode.commands.executeCommand(
- 'bpmnscript.decompile',
+ `bpmnscript.${msg.type}`,
vscode.Uri.parse(msg.uri),
);
}
@@ -95,7 +82,7 @@ export class SidebarViewProvider implements vscode.WebviewViewProvider {
}
}
- private async _postState(): Promise {
+ async refresh(): Promise {
if (!this._view) return;
const editor = vscode.window.activeTextEditor;
@@ -104,7 +91,7 @@ export class SidebarViewProvider implements vscode.WebviewViewProvider {
if (editor) {
const uri = editor.document.uri;
const ext = path.extname(uri.fsPath).toLowerCase();
- const kind: 'dsl' | 'bpmn' | null =
+ const kind: ActiveFile['kind'] =
ext === '.bpmnscript' ? 'dsl' : ext === '.bpmn' ? 'bpmn' : null;
activeFile = {
@@ -135,8 +122,6 @@ export class SidebarViewProvider implements vscode.WebviewViewProvider {
private _buildHtml(webview: vscode.Webview): string {
const nonce = randomBytes(16).toString('hex');
- const cspSource = webview.cspSource;
-
const cssUri = webview
.asWebviewUri(
vscode.Uri.joinPath(this._extensionUri, 'media', 'sidebar.css'),
@@ -153,14 +138,11 @@ export class SidebarViewProvider implements vscode.WebviewViewProvider {
'media',
'sidebar.html',
).fsPath;
- let html = fs.readFileSync(templatePath, 'utf-8');
-
- html = html
+ return fs
+ .readFileSync(templatePath, 'utf-8')
.replaceAll('{{NONCE}}', nonce)
- .replaceAll('{{CSP_SOURCE}}', cspSource)
+ .replaceAll('{{CSP_SOURCE}}', webview.cspSource)
.replace('{{CSS_URI}}', cssUri)
.replace('{{JS_URI}}', jsUri);
-
- return html;
}
}
diff --git a/packages/extension/test/bundled-conversion.e2e.test.ts b/packages/extension/test/bundled-conversion.e2e.test.ts
index 74b34c6..7739d57 100644
--- a/packages/extension/test/bundled-conversion.e2e.test.ts
+++ b/packages/extension/test/bundled-conversion.e2e.test.ts
@@ -103,8 +103,9 @@ describe('bundled asset resolution and transform under the shim', () => {
const { stdout } = result;
- expect(stdout).toContain('PROCESS_ID:invoice-approval');
- expect(stdout).toContain('bpmn:definitions');
+ const [idLine, ...xml] = stdout.split('\n');
+ expect(idLine).toBe('PROCESS_ID:invoice-approval');
+ expect(xml.join('\n')).toContain(' {
validate = validationHelper(services.BpmnScript);
});
-function expectMentions(text: string, mentions: readonly string[]): void {
- for (const mention of mentions) {
- expect(text, `expected to find "${mention}" in: ${text}`).toContain(
- mention,
- );
- }
-}
-
-// The wording belongs to the validator, the rest is this module's mapping.
-type DiagnosticPosition = Omit;
-
-type CompileOutcome =
- | { ok: true; reimportsAs: string }
- | { ok: false; kind: 'validation'; diagnostics: DiagnosticPosition[] };
-
type CompileRow = readonly [
title: string,
source: string,
- expected: CompileOutcome,
+ /** The process id the output imports back as, or the whole failure. */
+ expected: string | Extract,
];
describe('compileDslToBpmn', () => {
@@ -60,7 +49,7 @@ describe('compileDslToBpmn', () => {
[
'the invoice-approval example compiles to BPMN that imports back under its own id',
fs.readFileSync(INVOICE_APPROVAL_SRC, 'utf-8'),
- { ok: true, reimportsAs: 'invoice-approval' },
+ 'invoice-approval',
],
[
'a type mismatch blocks the compile and reports the comparison it rejected',
@@ -74,6 +63,8 @@ describe('compileDslToBpmn', () => {
character: 6,
endLine: 2,
endCharacter: 17,
+ message:
+ "variable 'name' of type 'string' cannot be used in an ordered comparison with '>'",
severity: 1,
text: 'name > 1000',
},
@@ -83,29 +74,22 @@ describe('compileDslToBpmn', () => {
[
'an undeclared variable is only a warning, so the source still compiles',
`process p { if (amount > 1000) { user A } }`,
- { ok: true, reimportsAs: 'p' },
+ 'p',
+ ],
+ [
+ 'a comment-only file is refused in plain words, not in astToIr wording',
+ '// nothing but a comment here\n',
+ { ok: false, kind: 'error', message: 'the file has no process' },
],
])('%s', async (_title, source, expected) => {
const result = await compileDslToBpmn(source, '0.0.1');
- expect(result.ok).toBe(expected.ok);
- if (expected.ok) {
- if (!result.ok) return;
- expect(result.output).toContain('bpmn:definitions');
- expect((await xmlToIr(result.output)).ir.id).toBe(expected.reimportsAs);
+ if (typeof expected !== 'string') {
+ expect(result).toEqual(expected);
return;
}
-
- if (result.ok) return;
- expect(result.kind).toBe(expected.kind);
- expect('output' in result).toBe(false);
- if (result.kind !== 'validation') return;
- expect(
- result.diagnostics.map(({ message: _message, ...position }) => position),
- ).toEqual(expected.diagnostics);
- expect(result.diagnostics.map((d) => d.message.length > 0)).toEqual(
- expected.diagnostics.map(() => true),
- );
+ if (!result.ok) throw new Error(JSON.stringify(result));
+ expect((await xmlToIr(result.output)).ir.id).toBe(expected);
});
// `bpmn-auto-layout`'s grid solver throws on this validator-clean shape: a
@@ -132,20 +116,9 @@ describe('compileDslToBpmn', () => {
if (!result.ok) return;
expect(result.output).toContain(' {
- const result = await compileDslToBpmn(
- '// nothing but a comment here\n',
- '0.0.1',
+ expect(result.layoutWarning).toMatch(
+ /^'bpmn-auto-layout' failed to lay out the process: \S/,
);
-
- expect(result).toEqual({
- ok: false,
- kind: 'error',
- message: 'the file has no process',
- });
});
});
@@ -186,33 +159,58 @@ const CONDITIONAL_START_BPMN = `
`;
-type DecompileOutcome =
- | {
- ok: true;
- /** Every warning, as [element id, category], in the order reported. */
- warnings: (readonly [string, string])[];
- mentions: string[];
- }
- | { ok: false; kind: 'unsupported'; mentions: string[] };
-
-type DecompileRow = readonly [
- title: string,
- xml: string,
- expected: DecompileOutcome,
-];
+// A number field whose default the engine's `LongFormType` cannot convert:
+// imported as written, refused by the validator.
+const DECIMAL_DEFAULT_BPMN = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
describe('decompileBpmnToDsl', () => {
- test.each([
+ test.each<[title: string, xml: string, expected: DecompileResult]>([
[
'a lane and an unsupported engine attribute are dropped with a warning each, naming the element they came off',
LANE_AND_ASYNC_ATTR_BPMN,
{
ok: true,
+ output: `process warns {
+ start S
+ user AsyncTask(assignee: "alice", asyncBefore: true)
+ end E
+}
+`,
warnings: [
- ['Lane_Ops', 'lane'],
- ['AsyncTask', 'extensionAttribute'],
+ {
+ elementId: 'Lane_Ops',
+ category: 'lane',
+ message:
+ "lane 'Ops' (Lane_Ops) was not imported\n" +
+ 'note: every step is placed in a single flat process',
+ },
+ {
+ elementId: 'AsyncTask',
+ category: 'extensionAttribute',
+ message:
+ "setting 'operaton:formHandlerClass' on 'AsyncTask' was not imported\n" +
+ "note: BPMNscript reads no such setting on a 'bpmn:userTask'\n" +
+ 'note: the rebuilt document carries none',
+ },
],
- mentions: ['formHandlerClass'],
+ buildErrors: [],
},
],
[
@@ -221,39 +219,80 @@ describe('decompileBpmnToDsl', () => {
{
ok: false,
kind: 'unsupported',
- mentions: ['BadService_1', 'no execution discriminator'],
+ message:
+ "service task 'BadService_1' uses an unsupported execution form: no execution discriminator\n" +
+ 'note: the supported forms are a Java class, an expression, a delegate expression, an external task topic, a built-in mail or shell task with its fields, or a decision reference on a business rule task\n' +
+ "note: their attributes are 'operaton:class' (or the deprecated 'camunda:class' alias), 'operaton:expression', 'operaton:delegateExpression', 'operaton:type=\"external\"' with 'operaton:topic', 'operaton:type=\"mail\"' or 'operaton:type=\"shell\"' with their 'operaton:field' children, and 'operaton:decisionRef'",
},
],
[
'a conditional start event comes back as a script the compiler accepts',
CONDITIONAL_START_BPMN,
- { ok: true, warnings: [], mentions: [] },
+ {
+ ok: true,
+ output: `process conditional {
+ var stockLevel: any
+ start ConditionalStart condition(stockLevel < 5)
+ end E
+}
+`,
+ warnings: [],
+ buildErrors: [],
+ },
+ ],
+ [
+ 'the printed script is re-validated, so an error it draws is reported while the script is still returned',
+ DECIMAL_DEFAULT_BPMN,
+ {
+ ok: true,
+ output: `process decimal-default-carry {
+ start S
+ user Review {
+ form {
+ amount: number = 1.5
+ }
+ }
+ end E
+}
+`,
+ warnings: [
+ {
+ elementId: 'Review',
+ category: 'carriedAsWritten',
+ message:
+ "the engine cannot use default '1.5' on form field 'amount' of 'Review' as written\n" +
+ "note: 'LongFormType.convertValue' parses it with 'Long.valueOf' on every render of the form, and it is not an integer\n" +
+ 'note: it was imported as written, and the printed script draws an error at the field',
+ },
+ ],
+ buildErrors: [
+ {
+ line: 4,
+ character: 23,
+ endLine: 4,
+ endCharacter: 26,
+ message:
+ "the default 1.5 of number field 'amount' is not an integer\n" +
+ 'note: the engine converts it with Long.valueOf every time the form renders and throws on anything else',
+ severity: 1,
+ text: '1.5',
+ },
+ ],
+ },
],
])('%s', async (_title, xml, expected) => {
const result = await decompileBpmnToDsl(xml);
- expect(result.ok).toBe(expected.ok);
- if (expected.ok) {
- if (!result.ok) return;
- expect(result.warnings.map((w) => [w.elementId, w.category])).toEqual(
- expected.warnings,
- );
- expectMentions(
- result.warnings.map((w) => w.message).join('\n'),
- expected.mentions,
- );
- // Parsing alone accepts source the validator refuses. Warnings are
- // expected: a BPMN declares no variables.
- const { diagnostics } = await validate(result.output);
- expect(
- diagnostics.filter((d) => d.severity === 1).map((d) => d.message),
- ).toEqual([]);
- return;
- }
-
- if (result.ok) return;
- expect(result.kind).toBe(expected.kind);
- expectMentions(result.message, expected.mentions);
+ expect(result).toEqual(expected);
+ if (!result.ok) return;
+ // Parsing alone accepts source the validator refuses, so the script goes
+ // through the validator, whose errors are exactly the reported ones.
+ const { diagnostics } = await validate(result.output);
+ expect(
+ diagnostics
+ .filter((d) => d.severity === 1)
+ .map((d) => Diagnostic.getMessageString(d)),
+ ).toEqual(result.buildErrors.map((e) => e.message));
});
// The file picker offers every file, and the message goes into a
@@ -264,7 +303,7 @@ describe('decompileBpmnToDsl', () => {
[
'a long file that is not XML at all is named by a short preview of its start',
'PK\u0003\u0004' + 'x'.repeat(300_000),
- `not an XML document (starts with "PK${'x'.repeat(38)}")`,
+ `not an XML document (starts with 'PK${'x'.repeat(38)}')`,
],
[
'a document the parser chokes on is cut to its first line, capped, and stripped of control characters',
diff --git a/packages/extension/test/conversion.test.ts b/packages/extension/test/conversion.test.ts
index 01e5250..251449f 100644
--- a/packages/extension/test/conversion.test.ts
+++ b/packages/extension/test/conversion.test.ts
@@ -9,6 +9,7 @@ const mocks = vi.hoisted(() => ({
showInformationMessage: vi.fn(),
showTextDocument: vi.fn(),
executeCommand: vi.fn(),
+ appendLine: vi.fn(),
}));
vi.mock('vscode', () => ({
@@ -25,6 +26,10 @@ vi.mock('vscode', () => ({
showInformationMessage: mocks.showInformationMessage,
showTextDocument: mocks.showTextDocument,
showOpenDialog: vi.fn(),
+ createOutputChannel: () => ({
+ appendLine: mocks.appendLine,
+ show: vi.fn(),
+ }),
},
commands: {
executeCommand: mocks.executeCommand,
@@ -78,13 +83,17 @@ function shownDocuments(): string[] {
);
}
+function outputLines(): string[] {
+ return mocks.appendLine.mock.calls.map((call) => String(call[0]));
+}
+
function executedCommands(): string[] {
return mocks.executeCommand.mock.calls.map((call) => String(call[0]));
}
-const SAME_WORDING =
- 'The model weighs the route on from here with a condition, ' +
- 'which the script leaves out.';
+const DROPPED = (id: string): string =>
+ `condition '\${ok}' on the route out of '${id}' was dropped\n` +
+ 'note: when the condition is false, Operaton stops the original process with an error';
type Expected = {
info?: string[];
@@ -93,6 +102,8 @@ type Expected = {
returns: string | undefined;
shown?: string[];
executed?: string[];
+ /** Lines written to the output channel, where note and help lines keep their own line. */
+ output?: string[];
};
type Row = readonly [
@@ -122,20 +133,40 @@ describe('conversion commands: what the author is shown', () => {
{
elementId: 'CheckStock',
category: 'droppedCondition',
- message: SAME_WORDING,
+ message: DROPPED('CheckStock'),
},
{
elementId: 'ReserveGoods',
category: 'droppedCondition',
- message: SAME_WORDING,
+ message: DROPPED('ReserveGoods'),
+ },
+ ],
+ buildErrors: [
+ {
+ line: 2,
+ character: 0,
+ endLine: 2,
+ endCharacter: 4,
+ message: 'bad default\nnote: it is not an integer',
+ severity: 1,
+ text: 'done',
},
],
},
{
info: ['BPMNscript: Decompiled "example.bpmn" -> "example.bpmnscript"'],
warning: [
- 'BPMNscript: "example.bpmn" reported 2 item(s) during decompile: ' +
- `CheckStock: ${SAME_WORDING}; ReserveGoods: ${SAME_WORDING}`,
+ 'BPMNscript: "example.bpmn" reported 2 item(s) during decompile.',
+ 'BPMNscript: The script decompiled from "example.bpmn" has 1 compilation error(s) and needs hand-repair.',
+ ],
+ output: [
+ 'BPMNscript: "example.bpmn" reported 2 item(s) during decompile.',
+ " condition '${ok}' on the route out of 'CheckStock' was dropped\n" +
+ ' note: when the condition is false, Operaton stops the original process with an error',
+ " condition '${ok}' on the route out of 'ReserveGoods' was dropped\n" +
+ ' note: when the condition is false, Operaton stops the original process with an error',
+ 'BPMNscript: The script decompiled from "example.bpmn" has 1 compilation error(s) and needs hand-repair.',
+ ' line 3: bad default\n note: it is not an integer',
],
returns: '/tmp/example.bpmnscript',
shown: ['/tmp/example.bpmnscript'],
@@ -148,12 +179,19 @@ describe('conversion commands: what the author is shown', () => {
{
ok: false,
kind: 'unsupported',
- message: 'multiple linked processes (pools and message flows).',
+ message:
+ "the file contains two executable processes ('a', 'b')\n" +
+ 'note: BPMNscript imports one process',
},
{
error: [
- 'BPMNscript: "example.bpmn" contains an unsupported construct: ' +
- 'multiple linked processes (pools and message flows).',
+ 'BPMNscript: "example.bpmn" cannot be decompiled: ' +
+ "the file contains two executable processes ('a', 'b')",
+ ],
+ output: [
+ 'BPMNscript: "example.bpmn" cannot be decompiled: ' +
+ "the file contains two executable processes ('a', 'b')",
+ ' note: BPMNscript imports one process',
],
returns: undefined,
},
@@ -203,8 +241,8 @@ describe('conversion commands: what the author is shown', () => {
undefined,
{
warning: [
- 'BPMNscript: "example.bpmnscript" is not a .bpmn file; ' +
- 'use "Compile to BPMN" for it.',
+ 'BPMNscript: "example.bpmnscript" is not a .bpmn file. ' +
+ 'Use "Compile to BPMN" for it.',
],
returns: undefined,
},
@@ -272,11 +310,13 @@ describe('conversion commands: what the author is shown', () => {
error = [],
shown = [],
executed = [],
+ output = [],
} = expected;
expect(returned?.fsPath).toBe(expected.returns);
expect(notifications()).toEqual({ info, warning, error });
expect(shownDocuments()).toEqual(shown);
expect(executedCommands()).toEqual(executed);
+ expect(outputLines()).toEqual(output);
const core = command === 'compile' ? compileDslToBpmn : decompileBpmnToDsl;
expect(core).toHaveBeenCalledTimes(result === undefined ? 0 : 1);
@@ -324,6 +364,9 @@ describe('conversion commands: what reaches the disk', () => {
);
expect(returned?.fsPath).toBe(returns);
+ expect(notifications().warning).toEqual([
+ '"/tmp/example.bpmn" already exists. Overwrite?',
+ ]);
expect(vscode.workspace.fs.writeFile).toHaveBeenCalledTimes(writes);
});
diff --git a/packages/extension/test/injection-grammar.test.ts b/packages/extension/test/injection-grammar.test.ts
index 2e880cb..b9c1724 100644
--- a/packages/extension/test/injection-grammar.test.ts
+++ b/packages/extension/test/injection-grammar.test.ts
@@ -52,7 +52,9 @@ function matchFence(line: string): { name: string; rule: any } | undefined {
describe('fenced-script injection grammar', () => {
it('is registered against source.bpmn-script at a path build:prepare copies it to', () => {
- expect(injection.injectionSelector).toContain('source.bpmn-script');
+ expect(injection.injectionSelector).toBe(
+ 'L:source.bpmn-script -comment -string',
+ );
const entry = pkg.contributes.grammars.find(
(g: { scopeName: string }) => g.scopeName === injection.scopeName,
@@ -60,7 +62,7 @@ describe('fenced-script injection grammar', () => {
expect(entry).toBeDefined();
expect(entry.injectTo).toEqual(['source.bpmn-script']);
expect(pkg.scripts['build:prepare']).toContain(
- `cp -f ./injection/bpmn-script.injection.tmLanguage.json ./${entry.path}`,
+ `fs.cpSync('injection/bpmn-script.injection.tmLanguage.json', '${entry.path}')`,
);
expect(() =>
readFileSync(path.join(EXTENSION_DIR, entry.path)),
@@ -93,7 +95,7 @@ describe('fenced-script injection grammar', () => {
expect(match!.rule.contentName, tag).toBe(
`meta.embedded.block.${format}`,
);
- expect(match!.rule.patterns, tag).toContainEqual({ include: embedded });
+ expect(match!.rule.patterns, tag).toEqual([{ include: embedded }]);
}
});
diff --git a/packages/extension/test/language-configuration.test.ts b/packages/extension/test/language-configuration.test.ts
index f9d8c01..38a8e85 100644
--- a/packages/extension/test/language-configuration.test.ts
+++ b/packages/extension/test/language-configuration.test.ts
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest';
import { readFileSync } from 'node:fs';
import * as path from 'node:path';
import { fileURLToPath } from 'node:url';
-import { ID_TERMINAL } from '@bpmn-script/language';
+import { ID_TERMINAL, QUOTED_NAME_TERMINAL } from '@bpmn-script/language';
const EXTENSION_DIR = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
@@ -20,7 +20,9 @@ function readWordPattern(): unknown {
}
describe('language configuration', () => {
- it("the editor's word pattern is the grammar's ID terminal", () => {
- expect(readWordPattern()).toBe(ID_TERMINAL.source);
+ it("the editor's word pattern is the grammar's QUOTED_NAME and ID terminals", () => {
+ expect(readWordPattern()).toBe(
+ `${QUOTED_NAME_TERMINAL.source}|${ID_TERMINAL.source}`,
+ );
});
});
diff --git a/packages/language/README.md b/packages/language/README.md
index 8c95cb7..12029a2 100644
--- a/packages/language/README.md
+++ b/packages/language/README.md
@@ -1,24 +1,14 @@
# @bpmn-script/language
-The Langium package: grammar, parser, AST, validator, and language server for BPMNscript.
-It's the reference for what counts as valid syntax, and the piece that turns source text into the tree the rest of the toolchain works on.
+The language reference for BPMNscript, and the Langium package that implements it: grammar, parser, AST, validator, and language server.
-The language's rules are written once, in `src/bpmn-script.langium`.
-[Langium](https://langium.org/) reads that grammar and generates a parser, the AST types as TypeScript interfaces, and a language server that powers highlighting, autocompletion, hover, navigation, rename, and inline diagnostics.
-None of the generated code is checked in; `npm run build` regenerates it.
+The grammar in [`src/bpmn-script.langium`](src/bpmn-script.langium) decides what parses.
+[Langium](https://langium.org/) generates the parser, the AST types, and a language server (highlighting, completion, hover, navigation, rename, inline diagnostics) from it; `npm run build` regenerates that code, and none of it is checked in.
+The validator, [`src/bpmn-script-validator.ts`](src/bpmn-script-validator.ts), adds the rules a grammar can't express, such as "a service task needs exactly one binding" or "a variable must be used as its declared type".
-The hand-written part is the validator (`src/bpmn-script-validator.ts`), which covers the structural rules a parser can't express, such as "a service task needs exactly one binding attribute" or "a variable reference must match a declared `var` type".
-Langium already reports syntax errors and unresolved references, so the validator adds the BPMN-specific and type-system rules on top.
+The rest of this page teaches the language from the first process to the event layer, then lists the diagnostics and the package's own API and layout.
-The package also owns the base VS Code TextMate grammar (`syntaxes/bpmn-script.tmLanguage.json`, generated by `langium generate`, adjusted by `textmate-postprocess.mjs`, and git-ignored).
-`packages/extension` layers a hand-maintained injection grammar over it for embedded-language highlighting inside a `script` body; see [`packages/extension/README.md`](../extension/README.md).
-
-## The language
-
-Steps run top to bottom, so sequence flow is never written out, and control flow uses structured statements instead.
-Optional `var` declarations go in the process header, before the body, alongside the header's own settings: `versionTag`, which labels the deployed process definition, `historyTimeToLive`, `candidateStarterUsers` and `candidateStarterGroups`, whose entries are listed as candidate starters (Tasklist's process list; `BpmnDeployer.addAuthorizations` stores each entry as written), and `isStartableInTasklist`, an unquoted boolean that, set to `false`, hides the process from Tasklist's start list.
-`historyTimeToLive` is the number of days the engine keeps a finished instance's history, written `PD` or ``, and an absent value compiles to `P30D`, since `HistoryTimeToLiveParser.parseAndValidate` refuses a null value under the engine's default `enforceHistoryTimeToLive`; the cleanup itself runs only once its batch window is configured.
-Every header value is stored as written, never evaluated: `label`, `documentation` and `versionTag` are quoted strings, the tag at most 64 characters, and no header setting takes a `"${...}"` expression.
+## A first process
```bpmnscript
process invoice-approval {
@@ -35,126 +25,161 @@ process invoice-approval {
}
```
-An id is ASCII only: a letter or `_`, then any run of letters, digits and `_`, with single hyphens allowed between such runs (the `ID` terminal in the grammar).
-A step, a call and a sub-process derive the BPMN `name` from that id (`ReviewInvoice` becomes "Review Invoice") unless a `label` setting gives one instead: `user ReviewInvoice(label: "Review invoice")`; a `start` and an `end` are named by `label` alone, and `on`, `throw`, `emit` and `await` show no name at all.
-A `documentation` setting carries free-form text alongside `label`, spelled the same way: `user ReviewInvoice(documentation: "Escalate to the senior approver above 1000.")`.
-
-### Statements
-
-| Statement | What it means | BPMN element | Notes |
-| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
-| `process X { }` | the BPMN process, one per file | `bpmn:process` | header settings and `var` declarations go before the body, see [The language](#the-language) |
-| `var x: number` | declare a variable so its uses get type-checked | none | the importer declares `var x: any` for every variable the printed script reads and nothing else declares |
-| `start X` / `end X` | where the flow begins and ends | start event / end event | |
-| `start X (...)` | start when an event arrives | start event with a trigger | see [Starting on an event](#starting-on-an-event) |
-| `end X terminate` | stop every running path | terminate end event | see [Ending every path](#ending-every-path) |
-| `end X cancel` | give up the block of steps around this end | cancel end event | see [Giving a block of work up](#giving-a-block-of-work-up) |
-| `user X(...)` | a step a person performs | user task | assignment and form attributes, see below |
-| `form { x: number "Label" }` | a form on a `start` or a `user` step; each field fills a process variable when the form is submitted | form fields on the start event or user task | see [Forms](#forms) |
-| `service X(...)` | a step the system performs: in the engine, by an external worker that picks it up by topic, or as a built-in shell command or mail | service task; `topic` makes it the external type, `type` a built-in one | exactly one binding attribute, see below |
-| `script X` + a fenced body | an inline script, in JS, Groovy, Python, Ruby or FEEL | script task | fence tag picks the language, see below |
-| `step X(...)` | a step nothing in the engine automates | task | |
-| `send X(...)` | a step that sends something out | send task | binds like a service task, see below |
-| `receive X(...)` | wait here until a named message arrives, or until the engine is told to move on | receive task | see below |
-| `decide X(...)` | a step a decision table answers, or one bound like a service task | business rule task | see below |
-| `if (cond) (settings)` / `else if` / `else` | a decision: one branch runs | exclusive gateway | settings on the head only, see [Job settings on a gateway](#job-settings-on-a-gateway) |
-| `while (cond) (settings) { }` | a loop that checks its condition before each pass | exclusive gateway loop | see [Job settings on a gateway](#job-settings-on-a-gateway) |
-| `do { } while (cond) (settings)` | a loop that runs its body once before the first check | exclusive gateway loop | see [Job settings on a gateway](#job-settings-on-a-gateway) |
-| `parallel (settings) { { } { } }` | branches that run at the same time; a branch headed by `if` runs only when its condition holds, and an `else` branch only when no sibling's condition did | parallel gateway fork and join, or inclusive when a branch is conditioned | see [Conditioning a parallel branch](#conditioning-a-parallel-branch) and [Job settings on a gateway](#job-settings-on-a-gateway) |
-| `subprocess X(...) { }` | a group of steps as one unit | embedded sub-process | a nested container, see below |
-| `attempt X(...) { }` | a group of steps that can be given up as one | transaction sub-process | the same container, for work that can be given up, see [Giving a block of work up](#giving-a-block-of-work-up) |
-| `call X(...) { }` | start another process and wait for it | call activity | see below |
-| `goto X` | jump to a named step in the same container | sequence flow | see [What `goto` can reach](#what-goto-can-reach) |
-| `on { }` | catch an event anywhere in this body | event sub-process | see [The event layer](#the-event-layer) |
-| `on Host: { }` | catch an event only while `Host` runs | boundary event | see [Attaching a handler to one step](#attaching-a-handler-to-one-step) |
-| `await (...)` | stop here until the event arrives | intermediate catch event | see [Awaiting an event inline](#awaiting-an-event-inline) |
-| `await (settings) { (...) { } (...) { } }` | wait on several triggers, continue down whichever fires first | event-based gateway, a catch event per branch, exclusive join | see [Waiting on several triggers at once](#waiting-on-several-triggers-at-once) and [Job settings on a gateway](#job-settings-on-a-gateway) |
-| `throw` / `emit ` | raise an event, ending the path or continuing | throw event | see [The event layer](#the-event-layer) |
-| `emit link("X")` / `await link("X")` | jump to the catch of the same name, a diagram's off-page connector | intermediate throw and catch event, with no flow between them | see [Link events](#link-events) |
-| `for each x in c` | run a step once per item, or a set number of times | multi-instance marker | see [Repetition](#repetition) |
-| `asyncBefore: true` | engine settings: async, exclusive, priority, retries, or, with a `run` prefix, on each run of a repetition | `operaton:` attribute/element | see [Attribute keys per element](#attribute-keys-per-element) |
-| `input x = "..."` | data into a step's execution, and `output` back out | `operaton:inputOutput` | see [Input and output parameters](#input-and-output-parameters) |
-| `on create(class: "...")` | code on a step's lifecycle, not a caught event | execution / task listener | see [Listeners](#listeners) |
-
-Every statement in that table that takes settings of its own also takes the engine settings and an execution listener, and most of them take input and output parameters as well.
-The ten that map to an activity (`user`, `service`, `script`, `step`, `send`, `receive`, `decide`, `subprocess`, `attempt`, and `call`) also take a repetition clause between the id and the parens, see [Repetition](#repetition).
-A brace holds what has internal structure: the body of a `while`, `do`, `parallel`, `subprocess`, `attempt`, `on`, or multi-branch `await`, and the form fields, parameters, listeners, error mappings, and call mappings an element carries.
-The last four rows are members of an element rather than statements: the `for` clause is that repetition modifier, an engine setting joins the rest in the `( )`, a parameter and a listener go in the `{ }`, and not every element takes every one.
-The listener row reuses `on` instead of opening a new event sub-process; the body block a handler always carries and a listener never does is what tells the two apart ([ADR-0020](../../docs/decisions/0020-listeners-reuse-on-inside-the-attribute-block.md)).
-
-#### Attribute keys per element
-
-The grammar accepts any key in any element's parens and the validator decides which ones that element has, so an unknown key is a diagnostic naming the element rather than a parse error.
-Five engine execution settings are legal on every element that takes settings, `label` and `documentation` are legal on all of them too, and each element kind adds the keys it owns on top.
-
-| Element | Keys beyond the engine settings |
-| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
-| `start` | `initiator`, on the process's own start |
-| `end`, `await`, `on`, `subprocess`, `attempt` | none |
-| `user` | `assignee`, `formKey`, `formRef`, `binding`, `version`, `candidateGroups`, `candidateUsers`, `dueDate`, `followUpDate`, `priority` |
-| `service` | `class`, `expression`, `delegate`, `topic`, `type`, `resultVariable`, `taskPriority` |
-| `script` | `resultVariable` |
-| `step` | none |
-| `send` | `class`, `expression`, `delegate`, `topic`, `type`, `resultVariable`, `taskPriority` |
-| `receive` | `message` |
-| `decide` | `class`, `expression`, `delegate`, `topic`, `type`, `decision`, `binding`, `version`, `mapDecisionResult`, `resultVariable`, `taskPriority` |
-| `call` | `process`, `binding`, `version`, `businessKey`, `mapper`, `mapperDelegate` |
-| `throw`, `emit` | `class`, `expression`, `delegate`, `topic` (on a `message` trigger only) |
-| process header | `label`, `documentation`, `versionTag`, `historyTimeToLive`, `candidateStarterUsers`, `candidateStarterGroups`, `isStartableInTasklist` |
-
-The engine settings are `asyncBefore` and `asyncAfter`, which put a transaction boundary before or after the step, `exclusive`, which says whether the engine may run the step's jobs beside other jobs of the same instance, `jobPriority`, which orders those jobs in the queue, and `retryCycle`, the ISO cycle a failed job is retried on.
-`exclusive`, `jobPriority`, or `retryCycle` written without `asyncBefore` or `asyncAfter` beside it configures no job and draws a warning, since Operaton creates the job only from the async flags (BpmnParse.parseAsynchronousContinuation, DefaultFailedJobParseListener.parseActivity); a timer carrier is exempt, since the timer itself creates the job.
-A process's signal start, an awaited signal, and a signal race branch are exempt for `jobPriority` alone: the subscription job BpmnParse.parseSignalCatchEventDefinition declares for them takes its priority from the catcher and runs when the throwing side is async, while `exclusive` and `retryCycle` still reach that job only through the async flags.
-The gateways that `if`, `while`, `do...while`, `parallel`, and a multi-branch `await` synthesize take the same five settings on the statement head, see [Job settings on a gateway](#job-settings-on-a-gateway).
-`taskPriority` rides a `topic` binding alone, see [External task extras](#external-task-extras).
-A repeated step also takes `runAsyncBefore`, `runAsyncAfter`, `runExclusive`, and `runRetryCycle`, written to the repetition itself and read by the engine onto each run rather than around the whole loop.
-There is no `runJobPriority`: `jobPriority` already prices each run's job once a step repeats, because `createActivityOnScope` reads it off the step regardless of what repeats around it; the whole-loop job takes the process's own priority instead, see [Repetition](#repetition).
-
-A user task's `assignee` is the user id: a bare word or a quoted string reaches the engine as written, and `"${who}"` reads a variable.
-`candidateUsers` and `candidateGroups` are read the same way.
-`dueDate` and `followUpDate` take a period starting with `P`, an ISO date-time such as `"2026-01-01T09:00:00"`, or a `"${...}"` expression, the shapes `DueDateBusinessCalendar.resolveDuedate` parses when the task is created.
-`priority` is an integer or an expression yielding one; `TaskDecorator.initializeTaskPriority` parses a constant with `Integer.parseInt` at task creation, so `"high"` deploys and then fails the instance.
-A user task names its deployed form with `formKey` or with `formRef`, never both.
-`formRef` also needs `binding: latest`, `binding: deployment`, or `version: ` beside it, the same version-pinning a `call` or a `decide` step carries, since the engine refuses to deploy a form reference it cannot resolve a version for.
-`version` is a positive whole number, quoted or not, or an expression yielding one, on a `formRef`, a `call`, and a `decide` step alike: the engine parses it as an integer when the step runs (`BaseCallableElement.getVersion`, `TaskEntity.initializeFormRefFromTaskDefinition`), so `1.5` deploys and then fails the instance.
-
-#### Forms
-
-A process's own `start` and a `user` task each take one `form` block, `operaton:formData` on the wire, which Tasklist renders as one input per field and which fills one process variable per field when the form is submitted.
-A field takes the shape every element takes ([ADR-0011](../../docs/decisions/0011-structured-grammar-one-bracket-shape.md)): `id: type "label" = default (settings) { members }`, the label and the default optional.
-The parens hold what the engine validates a submission under, plus the date pattern; the braces hold what the field is built from, an `enum`'s values and its `property` lines.
-`id` is the process variable the field fills, so a `var` of the same name has to declare the same type.
+A file holds one process, which compiles to one `bpmn:process`.
+A second `process` in the same file is an error.
+Steps run top to bottom, so sequence flow is never written: control flow comes from structured statements such as `if`, `while` and `parallel`.
+Declarations (`var` and the event codes) go at the top of the body, before the first statement.
+`//` starts a line comment and `/* ... */` a block comment.
+
+Every element has the same shape ([ADR-0011](../../docs/decisions/0011-structured-grammar-one-bracket-shape.md)): a keyword, a name, then optional parens holding its settings, then optional braces holding what it is built from.
+`user ReviewInvoice(assignee: "demo")` has settings and no braces; a form, parameters and listeners go in the braces.
+
+## Names and labels
+
+A name is ASCII: a letter or `_`, then letters, digits and `_`, with single hyphens allowed between such runs (`invoice-approval`, never `Review-`).
+A name that form cannot spell, such as a keyword or `Task.1`, is written in backticks: `` user `Task.1` ``, `` goto `end` ``.
+The backticks are not part of the name, so `` `Review` `` and `Review` are one name, and a backslash takes the next character literally, so `` `a\`b` `` names ``a`b``.
+A step's name becomes its BPMN id, so even in backticks it holds only letters, digits, `_`, `-` and `.`, starting with a letter or `_`.
+An event code's name is no id and takes any text on one line: ``error `Payment failed`(code: "PF")``, thrown as ``throw error(`Payment failed`)``.
+A `field` or `property` key takes any text in backticks as well: ``property `true` = "yes"``.
+A variable has no backtick form; see [Variables](#variables).
+A step name is unique within the process, a step can't share the process's id, and a name can't match a pattern the compiler synthesizes ids from, its own or the diagram's `_di`, `BPMNDiagram_`, and `BPMNPlane_` ids ([ADR-0010](../../docs/decisions/0010-deterministic-synthesized-ids.md)).
+
+A step, a call and a sub-process take their diagram name from their id, so `ReviewInvoice` shows as "Review Invoice".
+A `label` setting replaces it: `user ReviewInvoice(label: "Review invoice")`.
+A `start` and an `end` show a name only when they carry a `label`, and `on`, `throw`, `emit` and `await` take no `label` and show none, except a link event, which shows its link name.
+
+`documentation` attaches free-form text to the element, spelled like `label`: `user ReviewInvoice(documentation: "Escalate above 1000.")`.
+A value inside an element is documented by a key named for the word that introduces it:
+
+- `conditionDocumentation` on any condition: `if (amount > 1000, conditionDocumentation: "Large amounts need a second look.")`, and the same after `else if`, `while`, `do ... while`, a `parallel` branch's `if`, an `until (...)`, and `start S condition(...)`.
+- `timerDocumentation` on a timer: `await timer("PT1H", timerDocumentation: "...")`, `on timeout after "PT8H"(class: "a.B", timerDocumentation: "...")`.
+- `countDocumentation` and `eachDocumentation` on a repetition: `user R for 3 each line in lines(countDocumentation: "...", eachDocumentation: "...")`.
+
+## Variables
+
+`var : ` declares a process variable so its uses get type-checked.
+The types are `string`, `number`, `boolean`, `date`, `json`, and `any`.
+Reading a variable nothing declares draws a warning, using it against its declared type an error, and declaring one twice an error.
+A form field, a catch binding, a parameter and a repetition's element declare a variable as well, and the repetition variables listed under [Repetition](#repetition) need no declaration.
+The importer declares `var x: any` for every variable a printed script reads and nothing else declares ([ADR-0015](../../docs/decisions/0015-the-print-declares-every-variable-it-reads.md)).
+
+A variable named like a reserved word, such as `process`, is written as the raw expression `"${process}"`.
+A name that ends up in an engine expression can't be a JUEL reserved word or contain a hyphen; the reserved words are `empty`, `div`, `mod`, `not`, `and`, `or`, `le`, `lt`, `eq`, `ne`, `ge`, `gt`, and `instanceof`, plus the literals `true`, `false`, and `null`.
+The same words are refused as a property read inside a `"${...}"` template, such as `"${order.and}"`.
+
+## Expressions
+
+Conditions are parsed into a real expression tree over a subset of JUEL, the engine's expression language:
+
+- integer, decimal, string, boolean, and `null` literals,
+- variable references with `.property` and `[index]` accessors,
+- unary `!` and `-`, arithmetic, comparison, `&&` and `||`, the ternary `? :`, and parentheses.
+
+Anything outside that subset is written as a quoted raw template, `"${...}"` or `"#{...}"`, passed to the engine as written.
+A raw template uses the escapes of a string literal, so `"${fn(\"a\")}"` is the expression `${fn("a")}` ([ADR-0032](../../docs/decisions/0032-expressions-raw-templates-and-escapes.md)).
+A condition whose static type is not boolean is an error, and so is a template with two `${...}` parts, such as `"${a} ${b}"`, used as an operand.
+`on condition(...)` and `await condition(...)` use the same grammar and the same checks as `if`.
+
+## Statements
+
+| Statement | What it does | BPMN element |
+| ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------ |
+| [`process X(...) { }`](#the-process-header) | the process | `bpmn:process` |
+| [`var x: number`](#variables) | declares a variable for type checking | none |
+| `start X` / `end X` | where the flow begins and ends | start event / end event |
+| [`start X (...)`](#starting-on-an-event) | starts the process when an event arrives | start event with a trigger |
+| [`end X terminate`](#ending-every-path) | stops every running path | terminate end event |
+| [`end X cancel`](#giving-a-block-of-work-up) | gives up the `attempt` block around it | cancel end event |
+| [`user X(...)`](#user-tasks) | a step a person performs | user task |
+| [`service X(...)`](#service-tasks) | a step the system performs | service task |
+| [`script X` + a fenced body](#script-tasks) | an inline script | script task |
+| `step X(...)` | a step nothing in the engine automates | task |
+| [`send X(...)`](#send-receive-and-decision-tasks) | a step that sends something out | send task |
+| [`receive X(...)`](#send-receive-and-decision-tasks) | waits for a message | receive task |
+| [`decide X(...)`](#send-receive-and-decision-tasks) | a step a decision table answers | business rule task |
+| [`if (c) { } else if (c) { } else { }`](#decisions-and-loops) | runs one branch | exclusive gateway |
+| [`else fail`](#stopping-when-no-condition-holds) | stops the run with an error when no condition holds | no default flow |
+| [`while (c) { }`](#decisions-and-loops) | checks before each pass | exclusive gateway loop |
+| [`do { } while (c)`](#decisions-and-loops) | runs the body once before the first check | exclusive gateway loop |
+| [`parallel { { } { } }`](#conditioning-a-parallel-branch) | runs branches at the same time, optionally conditioned | parallel gateways, or inclusive when a branch is conditioned |
+| [`goto X`](#what-goto-can-reach) | jumps to a named step in the same container | sequence flow |
+| [`subprocess X(...) { }`](#sub-processes) | groups steps into one unit | embedded sub-process |
+| [`attempt X(...) { }`](#giving-a-block-of-work-up) | a group of steps that can be given up as one | transaction sub-process |
+| [`call X(...) { }`](#call-activities) | starts another process and waits for it | call activity |
+| [`on { }`](#the-event-layer) | catches an event anywhere in the surrounding body | event sub-process |
+| [`on Host: { }`](#attaching-a-handler-to-one-step) | catches an event while `Host` runs | boundary event |
+| [`await (...)`](#awaiting-an-event-inline) | waits here until the event arrives | intermediate catch event |
+| [`await { (...) { } (...) { } }`](#waiting-on-several-triggers-at-once) | waits on several triggers and continues down whichever fires first | event-based gateway |
+| [`throw (...)` / `emit (...)`](#the-event-layer) | raises an event and ends the path, or raises it and continues | throw event |
+| [`emit link(...)` / `await link(...)`](#link-events) | jumps to the catch of the same name | link throw and catch events |
+
+An element also carries members, which are not statements:
+
+| Member | What it does | BPMN |
+| ----------------------------------------------------------------- | ---------------------------------------------------- | -------------------------- |
+| [`for each x in c`](#repetition) | runs a step once per item, or a set number of times | multi-instance marker |
+| [`asyncBefore: true`](#engine-settings) | an engine setting, in the parens | `operaton:` attribute |
+| [`form { ... }`](#forms) | a form on a `start` or a `user` step | `operaton:formData` |
+| [`input x = ...`, `output x = ...`](#input-and-output-parameters) | data into and out of a step | `operaton:inputOutput` |
+| [`field x = ...`](#field-injection) | a value injected into the step's Java implementation | `operaton:field` |
+| [`property x = ...`](#external-task-extras) | a key and text on a form field or an external task | `operaton:property` |
+| [`on create(class: "...")`](#listeners) | code run on a step's lifecycle | execution or task listener |
+
+Every element that takes settings takes the [engine settings](#engine-settings) and an execution listener, and most take input and output parameters.
+The ten activities (`user`, `service`, `script`, `step`, `send`, `receive`, `decide`, `subprocess`, `attempt`, and `call`) also take a repetition clause between the name and the parens.
+Inside an element's braces, `on` declares a listener; at statement position it declares an event handler, which always carries a body of statements ([ADR-0020](../../docs/decisions/0020-listeners-reuse-on-inside-the-attribute-block.md)).
+
+A few rules hold for every body:
+
+- A process, subprocess, attempt block, handler body, or loop body can't be empty, and an empty `if` or `parallel` branch draws a warning.
+- A step after an `end`, a `throw`, a `goto`, an `emit link`, or a block whose every branch ends that way can never run, which is an error, unless a `goto` targets it.
+ A `start`, an `await link`, or a handler can follow such a statement.
+- A `do` body that always ends or redirects the flow is an error, since nothing would reach the loop's check.
+- A parameter or listener written in a body rather than in an element's braces is an error.
+
+## The process header
+
+The parens after `process X` hold settings the engine stores as written and never evaluates, so none of them takes a `"${...}"` template:
-The type is `string`, `number`, `boolean`, `date`, or `enum`.
-`number` is written as `long` on the wire, the engine's own name for it, and an `enum` field stores the id of the chosen value, so its variable is a string.
+```bpmnscript
+process invoice-approval(label: "Invoice approval", versionTag: "1.2", historyTimeToLive: "P90D", candidateStarterGroups: "accounting, management", isStartableInTasklist: false) {
+ start Received
+ end Done
+}
+```
-Each setting in the parens but `pattern` is one `operaton:constraint`, evaluated in the order written.
-`FormValidators.createValidator` fails the deployment on any constraint name the engine has not registered, so the seven constraint names below, together with `pattern`, are the closed set the parens take.
+| Setting | Value |
+| ------------------------------------------------- | ----------------------------------------------------------------------------------- |
+| `label`, `documentation` | a quoted string |
+| `versionTag` | a quoted string of at most 64 characters, labeling the deployed process definition |
+| `historyTimeToLive` | days the engine keeps a finished instance's history, quoted as `"PD"` or `""` |
+| `candidateStarterUsers`, `candidateStarterGroups` | quoted, comma-separated ids allowed to start the process from Tasklist |
+| `isStartableInTasklist` | an unquoted boolean; `false` hides the process from Tasklist's start list |
-| Setting | What the engine checks | Fits | Value |
-| ---------------------------------- | ----------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------- |
-| `required: true` | a value was submitted, or the variable or the default already holds one; empty text fails | any type | the literal `true` |
-| `readonly: true` | no value was submitted for the field | any type | the literal `true` |
-| `min: `, `max: ` | the submitted number is at least `n`, or below `n` (`MaxValidator.validate` is exclusive) | `number` | an integer literal or a quoted integer such as `"-5"` |
-| `minlength: `, `maxlength: ` | the submitted text has at least, or at most, `n` characters | `string` | an integer literal or a quoted integer |
-| `validator: "..."` | whatever the named class or expression decides | any type | a non-empty class name or a `"${...}"` expression |
-| `pattern: "..."` | nothing; it is the format a submitted date is parsed with, `datePattern` on the wire | `date` | quoted `SimpleDateFormat` letters, quoted runs, and non-letters, such as `"dd/MM/yyyy"` |
+An absent `historyTimeToLive` compiles to `"P30D"`, because the engine's default configuration refuses to deploy a process without one.
+History cleanup itself runs only once its batch window is configured in the engine.
+The header takes no engine settings.
-A flag is on while written and off otherwise, so `required: false` is an error telling you to leave the setting out.
-The bounds fit one type each: `AbstractNumericValidator.validate` throws on a submitted value that is not a number and `AbstractTextValueValidator.validate` on one that is not text, so a `min` on a `string` field would deploy and then fail every submission.
-All four take an integer, since a `number` field is an Operaton `long`, whose validator parses the bound with `Long.parseLong`, and a length is a character count.
-`validator` cannot be empty, the one shape `FormValidators.createValidator` refuses to deploy, and `pattern` builds a `java.text.SimpleDateFormat`, which throws on a letter outside that set.
+## Tasks
-A literal default is converted through the field's type on every render, exactly as a submitted value is (`FormFieldHandler.createFormField`).
-A `number` default has to be an integer, which `LongFormType.convertValue` reads with `Long.valueOf`; a `boolean` default has to be `true` or `false`, since `BooleanFormType.convertValue` reads anything else as `false` with no error at all; and a `date` default with no `pattern` setting is read against the engine's own default, `"dd/MM/yyyy"` (`ProcessEngineConfigurationImpl.initFormTypes`), so an ISO-shaped default such as `"2026-01-01"` is refused unless a `pattern` says otherwise.
-A bare name or a `"${...}"` expression is left to the engine, since it is evaluated fresh at every render.
+### User tasks
-An `enum` field lists its values in the braces, one `id "Label"` line each in the order the form offers them, the label optional.
-One offering no values at all draws a warning rather than an error, since the engine deploys the form and then rejects every value submitted for the field.
-Its default, when it is a literal, has to name one of them: `FormFieldHandler.createFormField` converts the default through the type on every render of the form, so a default naming no value deploys and then fails to open.
-A `property = ""` line in the braces is an `operaton:property` on the field, a key and a text the engine parses into the form's description and never acts on itself.
-It is legal on a field of any type, and its value is a quoted string or a `"${...}"` expression, the shapes `field` takes.
-The same line sits in an external task's braces, where the engine keys it by `name` instead of `id`, see [External task extras](#external-task-extras).
+A `user` task is a step a person performs in Tasklist.
+
+- `assignee`, `candidateUsers` and `candidateGroups` take user or group ids: a bare word or a quoted string is passed as written, and `"${who}"` reads a variable.
+- `dueDate` and `followUpDate` take a period starting with `P`, an ISO date-time such as `"2026-01-01T09:00:00"`, or a `"${...}"` expression.
+- `priority` is an integer or an expression yielding one; `"high"` would deploy and then fail every instance.
+- `formKey` or `formRef` names a form deployed elsewhere, never both.
+ `formRef` also needs `binding: latest`, `binding: deployment`, or `version: ` beside it, since the engine refuses a form reference it cannot resolve a version for, and `binding` or `version` without a `formRef` is an error.
+
+`version` is a positive whole number, quoted or not, or an expression yielding one, here and on a `call` or a `decide` step; `1.5` would deploy and fail when the step runs.
+`binding` and `version` are mutually exclusive in all three places.
+
+### Forms
+
+A process's own `start` and a `user` task each take one `form` block, which Tasklist renders as one input per field.
+Each field fills the process variable of its name when the form is submitted, so a `var` of the same name has to declare the same type.
```bpmnscript
process gym-membership {
@@ -184,35 +209,75 @@ process gym-membership {
}
```
-#### Service tasks
+A field is `id: type "label" = default (settings) { members }`, with the label, default, settings and members optional.
+The type is `string`, `number`, `boolean`, `date`, or `enum`.
+`number` is the engine's `long`, and an `enum` field stores the id of the chosen value, so its variable is a string.
+Field ids are unique within a form.
+
+The parens take the engine's form constraints, checked in the order written, plus `pattern`, and nothing else:
+
+| Setting | What the engine checks | Fits | Value |
+| ---------------------------------- | ----------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------ |
+| `required: true` | a value was submitted, or the variable or default holds one; empty text fails | any type | the literal `true` |
+| `readonly: true` | no value was submitted for the field | any type | the literal `true` |
+| `min: `, `max: ` | the number is at least `n`, or below `n` (`max` is exclusive) | `number` | an integer, or a quoted integer such as `"-5"` |
+| `minlength: `, `maxlength: ` | the text has at least, or at most, `n` characters | `string` | an integer, or a quoted integer |
+| `validator: "..."` | whatever the named class or expression decides | any type | a non-empty class name or a `"${...}"` expression |
+| `pattern: "..."` | nothing; it is the format a submitted date is parsed with | `date` | `SimpleDateFormat` letters, quoted runs, and non-letters: `"dd/MM/yyyy"` |
+
+A flag is on when written and off otherwise, so `required: false` is an error telling you to leave it out.
+A bound on the wrong type would deploy and then fail every submission, so it's an error.
+
+A literal default is converted through the field's type every time the form renders.
+A `number` default has to be an integer and a `boolean` default `true` or `false` (the engine reads anything else as `false`).
+A `date` default is read against the field's `pattern`, or against the engine's default `dd/MM/yyyy` when there is none, so `"2026-01-01"` needs a matching `pattern`.
+A bare name or a `"${...}"` default is evaluated by the engine at each render and not checked.
+
+An `enum` field lists its values in the braces, one `id "Label"` line each in the order the form offers them, the label optional.
+Value ids are unique, a literal default has to name one of them, and a value line on a field that is not an `enum` is an error.
+An `enum` with no values draws a warning, since the engine deploys it and then rejects every submission.
+
+A `property = ""` line in a field's braces attaches a key and text that a custom form can read; the engine itself never acts on it.
+It fits any field type, its value is a quoted string or a `"${...}"` expression, and it is the only other member a field's braces take.
+
+A `form` block on any element other than a process's own `start` or a `user` task is an error.
+
+### Service tasks
+
+A `service` task takes exactly one of five bindings, which say what runs it ([ADR-0017](../../docs/decisions/0017-service-task-bindings.md)):
+
+| Binding | Value | What runs |
+| ------------ | ------------------------------------ | ----------------------------------------------------------------------------------------- |
+| `class` | a Java class name, loaded as written | that `JavaDelegate` |
+| `expression` | a `"${...}"` template or a bare name | the expression itself |
+| `delegate` | a `"${...}"` template or a bare name | the delegate object the expression resolves to |
+| `topic` | a topic name | an external worker fetching that topic, see [External task extras](#external-task-extras) |
+| `type` | `"mail"` or `"shell"` | a behaviour built into the engine, see [Mail and shell tasks](#mail-and-shell-tasks) |
-A `service` task takes exactly one of five binding attributes.
-`class` is a Java delegate class name, `expression` maps to `operaton:expression`, `delegate` is the friendlier spelling of `operaton:delegateExpression`, `topic` hands the work to an external worker through `operaton:type="external"` and `operaton:topic`, and `type` selects a behaviour Operaton builds itself, see [Mail and shell tasks](#mail-and-shell-tasks).
-`expression:` and `delegate:` take a `"${...}"` template or a bare name, never a quoted string: the engine evaluates the value, so quoted text under `delegate:` reaches it as a string that resolves to no delegate, and under `expression:` as a string that evaluates to itself and runs nothing.
-`class:` takes a class name alone, loaded as written, so a template there is not evaluated.
-`resultVariable` names the process variable the invocation's return value is stored in, and is not itself a binding.
-It is legal beside `expression:`, where the engine stores the return value, and beside `decision:` on a `decide` task, where it holds the decision result.
-Beside `topic:` and `type:` it is deployed and never written, since `BpmnParse.parseServiceTaskLike` hands it to the `expression` binding alone, so the validator warns; beside `class:` and `delegate:` it is refused, because the engine refuses to deploy that combination.
+Quoted text under `delegate` is an error, since it resolves to no delegate, quoted text under `expression` draws a warning, since it evaluates to itself and runs nothing, and a template under `class` is an error, since a class name is never evaluated.
+An empty binding value is an error.
-#### Send, receive, and decision tasks
+`resultVariable` names the variable the return value is stored in, and only an `expression` binding writes it.
+Beside `class` or `delegate` it is an error, since the engine refuses to deploy the combination; beside `topic` or `type` it deploys and is never written, so it draws a warning.
-A `send` task binds exactly the way a `service` task does: the same five attributes, and the same `resultVariable`.
-Operaton runs both through the same execution factory, so the tag changes what the diagram calls the step, not what the engine does with it.
+### Send, receive, and decision tasks
+
+A `send` task binds exactly like a `service` task, with the same five bindings and the same `resultVariable` rules.
+The engine runs both the same way, so the keyword changes how the diagram draws the step, not what it does.
It carries no message name of its own, unlike `receive` or `await message`.
-A `receive` task with `message` set waits for a message of that name, released by a correlation the same way an `await message` statement is.
-With no `message` key it still waits, but names nothing to correlate on: only the engine's own signal API can move the token past it.
+A `receive` task with `message: "Name"` waits for a message of that name, correlated the same way as an `await message`.
+Without `message` it still waits, but only the engine's signal API can move it on.
-A `decide` task answers a decision table when `decision` names one.
-`binding: latest` or `binding: deployment` pins the deployed version the same way a `call` does, `version: ` pins a specific one, and `mapDecisionResult` picks what lands in `resultVariable`: `singleEntry`, `singleResult`, `collectEntries`, or `resultList`.
-`mapDecisionResult` without a `resultVariable` is built and never applied (`DecisionEvaluationUtil.evaluateDecision` maps only when storing), so the validator warns.
-With no `decision` key it falls back to the same five binding attributes a `service` task takes, serialized as a `bpmn:businessRuleTask` instead of a `bpmn:serviceTask`, and `binding`, `version` and `mapDecisionResult` are refused there, since `BpmnParse.parseBusinessRuleTask` reads them on the decision path alone.
+A `decide` task with `decision: ""` evaluates that decision table.
+`binding: latest`, `binding: deployment`, or `version: ` pins the deployed table version, as on a `call`.
+`mapDecisionResult` picks what lands in `resultVariable`: `singleEntry`, `singleResult`, `collectEntries`, or `resultList`; without a `resultVariable` it is never applied and draws a warning.
+Without `decision`, a `decide` task binds like a `service` task, and `binding`, `version` and `mapDecisionResult` are errors there.
-#### Mail and shell tasks
+### Mail and shell tasks
-`type: "mail"` and `type: "shell"` select a behaviour Operaton builds itself, on a `service`, `send`, or `decide` task.
-A thrown message cannot bind one, since it opens no member block to carry the fields either behaviour requires.
-Each field rides `field = ` the same way a `class` or `delegate` binding's fields do, see [Field injection](#field-injection).
+`type: "mail"` and `type: "shell"` select a behaviour the engine builds itself, on a `service`, `send`, or `decide` task.
+Each input is a `field = ` line in the braces, like [field injection](#field-injection) into a class.
```bpmnscript
process notify-ops {
@@ -231,22 +296,80 @@ process notify-ops {
```
A mail task needs `to` and one of `text` or `html`; `cc` and `bcc` satisfy neither.
-`from` sets the sender address; left unset, `MailActivityBehavior` falls back to the process engine's configured default sender.
-`charset` sets the message's character encoding.
+`from` sets the sender, falling back to the engine's configured default, `subject` the subject line, and `charset` the encoding.
+
A shell task needs `command`.
-`arg1` through `arg5` are positional arguments appended after `command`, in order; `ShellActivityBehavior` skips any left unset.
-`directory` sets the working directory the command runs in; left unset, it runs in the engine process's own.
-Every shell field is a quoted literal, never a `"${...}"` expression, and its three flags, `wait`, `redirectError`, and `cleanEnv`, are written `true` or `false`.
-A shell task's output has no `resultVariable` of its own to hold it.
-`field outputVariable = "..."` names the process variable the command's stdout is written to, and `field errorCodeVariable = "..."` the one its exit code is written to.
-`resultVariable` beside `type:` is deployed and never written, the same as beside `topic:`, and draws the same warning.
+`arg1` to `arg5` are positional arguments appended after it in order, unset ones skipped, and `directory` sets the working directory, which defaults to the engine process's own.
+`outputVariable` names the variable that receives the command's stdout and `errorCodeVariable` the one that receives its exit code.
+Every shell field is a quoted literal, never an expression, and the flags `wait`, `redirectError`, and `cleanEnv` are `"true"` or `"false"`.
+
+A missing required field is an error, and so is a field name the behaviour does not know.
+`resultVariable` beside `type` draws the same warning as beside `topic`.
+
+### Script tasks
+
+A `script` task's body is a fenced block after the settings, whose opening tag names the language:
+
+````bpmnscript
+process tally {
+ script Count(resultVariable: "total") ```groovy
+ return 40 + 2
+ ```
+}
+````
+
+The tags are `juel`, `javascript`, `js` or `ecmascript`, `groovy`, `python` or `py`, `ruby` or `rb`, and `feel`, in any case.
+The tag runs to the first whitespace, so on a one-line fence a space separates it from the code.
+Only `juel` runs on every Operaton installation; the others need a JSR-223 script engine on the engine's classpath, which is looked up the first time the script runs, not at deployment.
+An unknown tag, an empty body, and an unterminated fence are errors, here and on every other fenced script (a listener, a parameter value).
+
+## What an element carries
+
+### Engine settings
-#### Input and output parameters
+Five engine settings are legal on every element that takes settings:
-`input = ` and `output = ` map data across a step's boundary as `operaton:inputParameter` and `operaton:outputParameter` entries in its `operaton:inputOutput` block, and are legal on a `user`, `service`, `script`, `step`, `send`, `receive`, or `decide` task, a `subprocess`, an `attempt` block, and a `call`.
-An `on` handler takes none in either form: a hosted `on :` handler lowers to a boundary event and a host-less one to an event sub-process, and the engine refuses to deploy either with one (`BpmnParse.parseBoundaryEvents`, `BpmnParse.checkActivityInputOutputSupported`).
-A value is an ordinary expression, a `[ ... ]` list, a `{ key: value }` map, or a fenced script that computes it, and lists and maps nest freely.
-Entries keep the order they were written in, and a name may repeat across the two directions but not within one.
+- `asyncBefore` and `asyncAfter` put a transaction boundary before or after the step, so the engine continues it in a job.
+- `exclusive` says whether that job may run beside other jobs of the same instance.
+- `jobPriority` orders the job in the queue.
+- `retryCycle` is the ISO cycle a failed job is retried on, such as `"R3/PT10M"`.
+
+`asyncBefore`, `asyncAfter` and `exclusive` are unquoted booleans, and `retryCycle` is quoted.
+A `retryCycle` the engine cannot read is dropped at deployment rather than refused, so it draws a warning.
+`jobPriority` is an integer or a `"${...}"` expression.
+
+The job exists only when `asyncBefore` or `asyncAfter` is set, so `exclusive`, `jobPriority`, or `retryCycle` without one of them configures nothing and draws a warning.
+Two cases are exempt.
+A timer catch creates its own job, so the three settings apply to it directly.
+A process's signal start, an `await signal`, and a signal branch of an `await { }` take `jobPriority` alone without an async flag, since the engine prices their subscription job with it; a signal handler or boundary keeps the warning.
+
+Each element owns further keys on top, and any other key is an error naming the element:
+
+| Element | Keys it owns |
+| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `start` | `label`, `documentation`, `initiator` (process start only) |
+| `end`, `step`, `subprocess`, `attempt` | `label`, `documentation` |
+| `user` | `label`, `documentation`, `assignee`, `formKey`, `formRef`, `binding`, `version`, `candidateGroups`, `candidateUsers`, `dueDate`, `followUpDate`, `priority` |
+| `service`, `send` | `label`, `documentation`, `class`, `expression`, `delegate`, `topic`, `type`, `resultVariable`, `taskPriority` |
+| `script` | `label`, `documentation`, `resultVariable` |
+| `receive` | `label`, `documentation`, `message` |
+| `decide` | `label`, `documentation`, `class`, `expression`, `delegate`, `topic`, `type`, `decision`, `binding`, `version`, `mapDecisionResult`, `resultVariable`, `taskPriority` |
+| `call` | `label`, `documentation`, `process`, `binding`, `version`, `businessKey`, `mapper`, `mapperDelegate` |
+| `throw`, `emit` | `class`, `expression`, `delegate`, `topic`, on a `message` trigger only |
+| `on` | the flag `alongside` |
+| `await`, a branch of `await { }` | none |
+
+A repeated step also takes the `run*` settings described under [Repetition](#repetition), and the gateway statements take settings on their head, see [Job settings on a gateway](#job-settings-on-a-gateway).
+The same key twice in one element is an error, and so is a value in a shape the element cannot read, such as a quoted `asyncBefore` or an unquoted `retryCycle`.
+
+The parens hold at most one unkeyed value, the payload of a trigger such as `message("Name")`.
+An unkeyed value where nothing reads one is an error (on a task, a call, a subprocess, a listener, the process header, or a `start` or `end` without a trigger, where `start S("PT30M")` is a timer missing its `timer` word), and so is a second unkeyed value.
+
+### Input and output parameters
+
+`input = ` and `output = ` in an element's braces map data into and out of the step.
+They are legal on every activity: a `user`, `service`, `script`, `step`, `send`, `receive`, or `decide` task, a `subprocess`, an `attempt` block, and a `call`.
+An `on` handler takes none, since the engine refuses to deploy a boundary event or an event sub-process with one.
```bpmnscript
process order-shipping {
@@ -258,12 +381,20 @@ process order-shipping {
}
```
-#### Field injection
+A value is an expression, a `[ ... ]` list, a `{ key: value }` map, or a fenced script that computes it, and lists and maps nest.
+A map key is a name or a quoted string.
+Entries keep their written order, and a name may repeat across the two directions but not within one.
+An empty or blank string as a value, a list item, or a map value draws a warning, because the engine trims it and reads it as absent.
+A repeated step can't map an `output`, since the engine refuses that combination; an `input` is fine.
+
+### Field injection
-`field = ` sets a Java bean property on the class, the delegate expression, or the mail or shell behaviour a step's binding names, `operaton:field` on the wire.
-The value is a quoted string, injected literally, or a `"${...}"` expression, evaluated per invocation; a list, a map, and an inline script have no field slot to hold.
-A field rides a `class:`, `delegate:`, or `type:` binding and no other, since Operaton builds the field list for whichever of the three a binding names and hands it to none of `expression:`, `topic:`, or `decision:`.
-It is legal on a `service`, `send`, or `decide` task bound that way, and, `type:` aside, inside a listener's braces, since a listener binds the same way a service task does.
+`field = ` sets a property on the Java object a step's binding names: the `class`, the object a `delegate` resolves to, or the mail or shell behaviour of a `type` ([ADR-0018](../../docs/decisions/0018-forms-and-field-injection.md)).
+The value is a quoted string, injected as is, or a `"${...}"` expression, evaluated on each invocation.
+A list, a map, a script, an empty value, and a string opening with an escaped `\${` or `#{` are errors.
+
+A field is legal on a `service`, `send`, or `decide` task bound with `class`, `delegate`, or `type`, and in a listener bound with `class` or `delegate`.
+On any other binding, `expression`, `topic`, or `decision`, the engine would never inject it, so it is an error.
```bpmnscript
process claim-intake {
@@ -278,17 +409,15 @@ process claim-intake {
}
```
-#### External task extras
+### External task extras
+
+A `service`, `send`, or `decide` task bound with `topic` hands its work to an external worker, and three members exist for that binding alone:
-A `service`, `send`, or `decide` task bound with `topic:` hands its work to an external worker, and three more things ride that binding and no other.
-`taskPriority: ` in the parens is `operaton:taskPriority`, the priority a worker's fetch can order by: an integer, a quoted one such as `"-5"`, a bare variable name, or a `"${...}"` expression, since `parsePriority` fails the deployment on any other constant.
-A `property = ""` line in the braces is the same member a form field takes, written to the wire as `operaton:property name=` here and `id=` there, since `BpmnParseUtil.parseOperatonExtensionProperties` and `DefaultFormHandler.parseProperties` read the one tag by different attributes.
-A worker fetching the task with `includeExtensionProperties` receives the list.
-An `error when ` line is an `operaton:errorEventDefinition errorRef= expression=`: it raises the declared code (see [The event layer](#the-event-layer)) when the condition holds, checked on a failure the worker reports and again on a completion.
-`ExternalTaskEntity.evaluateThrowBpmnError` runs the mappings in the order written, and the first true one wins.
-Beside the process variables the condition may read `externalTask.errorMessage`, `externalTask.errorDetails`, and `externalTask.retries`, the names the engine resolves on an external task's execution and nowhere else, so `externalTask` inside a mapping draws no undeclared-variable warning and in an `if` it does.
-`parseExternalServiceTask` is the only reader of all three, so each is an error on a task bound with `class`, `expression`, `delegate`, `type`, or `decision`.
-Each is an error on a `throw message` or an `emit message` bound with a topic too: `parseServiceTaskLike` reads the priority and the mappings off the message definition there (the property list off the event element), but this surface writes none of them for a throw.
+- `taskPriority: ` in the parens is the priority a worker's fetch can order by: an integer, a quoted integer such as `"-5"`, a bare variable name, or a `"${...}"` expression.
+- `property = ""` in the braces is a key and text the worker receives when it fetches with `includeExtensionProperties`, the same line a form field takes.
+- `error when ` in the braces raises a declared [error code](#the-event-layer) when the condition holds, checked when the worker reports a failure and again on completion.
+ Mappings run in the written order and the first true one wins.
+ Beside the process variables, the condition can read `externalTask.errorMessage`, `externalTask.errorDetails`, and `externalTask.retries`.
```bpmnscript
process card-payment {
@@ -304,21 +433,22 @@ process card-payment {
}
```
-#### Listeners
+Each of the three is an error on any other binding, and on a `throw message` or `emit message` bound with `topic`.
+A mapping headed by a word other than `error`, missing its `when`, or naming an undeclared code is an error.
+
+### Listeners
-An element's braces also hold listeners, written with `on ` and the thing to run.
-An execution listener fires when the element starts or ends and is legal on every element that takes settings.
-A task listener fires on a step in a user task's lifecycle and is legal on a `user` task alone.
+A listener runs code on a step's lifecycle and goes in the element's braces as `on ` plus what to run.
-| Listener kind | Events |
-| ----------------- | ----------------------------------------------------------------- |
-| execution | `start`, `end` |
-| task, `user` only | `create`, `assignment`, `complete`, `update`, `delete`, `timeout` |
+| Listener | Legal on | Events |
+| --------- | ----------------------------- | ----------------------------------------------------------------- |
+| execution | every element taking settings | `start`, `end` |
+| task | a `user` task | `create`, `assignment`, `complete`, `update`, `delete`, `timeout` |
-A listener runs exactly one thing: `class`, `expression`, or `delegate` in its own parens, or a fenced script whose opening tag names the language.
-That is the same choice a service task binding makes, without the external `topic` or the built-in `type`, and each value takes the shape it takes there: a class name under `class`, a `"${...}"` template or a bare name under `expression` and `delegate`.
-A `class` or `delegate` binding also opens a brace block of its own, holding injected fields the same way a `service`, `send`, or `decide` task's braces do; see [Field injection](#field-injection).
-`on timeout` carries the timer that says when it runs, written as an `after`, `at`, or `every` particle and a time, and no other event takes one.
+A listener runs exactly one thing: a `class`, `expression`, or `delegate` in its parens, valued as on a service task, or a fenced script.
+A `class` or `delegate` listener may open braces holding [fields](#field-injection).
+`on timeout` carries the timer saying when it fires, an `after`, `at`, or `every` particle and a time, and no other event takes one.
+The same event may carry several listeners on one element, and each compiles to its own listener in the order written.
````bpmnscript
process claim-review {
@@ -332,36 +462,156 @@ process claim-review {
}
````
-An `on` inside an element's braces is a listener; an `on` at statement position is a caught BPMN event, told apart by what follows the header: a handler always carries a body of statements, and a listener's own braces, when it carries any, hold field declarations instead.
+## Control flow
-#### Script tasks
+### Decisions and loops
-A `script` task's body is a markdown-style fenced block whose opening tag names the language: `juel`, `javascript`/`js` (or `ecmascript`), `groovy`, `python`/`py`, `ruby`/`rb`, and `feel`.
-The tag runs to the first whitespace or line break, so on a one-line fence a space separates the tag from the code, and an imported `scriptFormat` such as `http://www.java.com/java` or `python3` prints as a tag the validator names whole.
-`juel` is the only one every Operaton deployment can run out of the box; the others need a JSR-223 engine on the deployment's classpath, which `ScriptingEngines.getScriptEngineForLanguage` resolves the first time the script runs rather than at deployment.
+`if (condition) { } else if (condition) { } else { }` runs the first branch whose condition holds.
+Without an `else`, the flow carries on after the chain when no condition holds.
+`while (condition) { }` checks before each pass, and `do { } while (condition)` runs the body once before the first check.
+Each compiles to exclusive gateways, a loop with a back edge.
-#### Sub-processes
+### Stopping when no condition holds
-A `subprocess` is a nested flow container mapping to `bpmn:subProcess`.
-Its body is a plain statement block using the same vocabulary as a process body, including another `subprocess`, and BPMN viewers render it expanded with its children inside the parent's bounds.
-The same statement takes a second head, `attempt`, for a block of work that can be given up as a unit, see [Giving a block of work up](#giving-a-block-of-work-up).
+Ending an `if` chain with `else fail` stops the run with an error when no condition holds, instead of carrying on.
-#### Call activities
+```bpmnscript
+process claim-routing {
+ var amount: number
-A `call` reads like a function call at the process boundary.
-`process: ""` names the process to start, an `in` mapping is an argument passed into it, and an `out` mapping is a value read back.
-`in *` and `out *` copy every variable rather than naming one.
-`version: ` pins a deployed version of the called process, while `binding: latest` and `binding: deployment` select the other two resolution modes, and the two are mutually exclusive.
-`businessKey: ""` sets the started instance's business key.
+ start ClaimReceived
+ if (amount <= 1000) {
+ user QuickReview
+ } else if (amount <= 50000) {
+ user FullReview
+ } else fail
+ end ClaimRouted
+}
+```
+
+The gateway gets no default flow, so the engine fails with `ENGINE-02004 No outgoing sequence flow ... could be selected` when nothing matches.
+That is an engine exception, not a BPMN error, so no `on error` handler catches it.
+The transaction that reached the gateway rolls back: a start request fails and leaves no instance, a task completion fails and leaves the task open, and behind an `asyncBefore` the job fails and raises an incident once its retries run out.
+An empty branch beside `else fail` is how a case carries on rather than failing, so it draws no warning.
-A `local` mapping (`in local x = y`) reads from or writes to variables belonging to the call step itself rather than to the whole process.
-It's rare when authoring, and exists mainly so diagrams that use step-local variables import faithfully.
+A `parallel` block whose every branch is conditioned takes the same closing `else fail`, see the next section.
+A loop takes none, and a word other than `fail` after `else` is an error.
+`fail` is special only in this position, so `var fail: boolean` is legal.
-`mapper: ""` and `mapperDelegate: "${bean}"` name a Java class or a bean that computes the mapping in code, `operaton:variableMappingClass` and `operaton:variableMappingDelegateExpression` on the wire; they take the shapes `class` and `delegate` take on a `service` task.
-Either one names an implementation of Operaton's `DelegateVariableMapping`, whose `mapInputVariables` runs after the declared `in` mappings and whose `mapOutputVariables` runs after the declared `out` ones.
-A mapper therefore adds to what the call declares rather than standing in for it, and sits beside any `in` and `out` mappings the same call carries.
-Writing both spellings on one call is an error, since Operaton would read the class and drop the delegate expression without saying so.
-A mapper is not one of the bindings field injection rides: Operaton hands a variable mapping no field list, so a `call` carries no `field`.
+### Conditioning a parallel branch
+
+`parallel { { } { } }` runs two or more branches at the same time and continues when all have finished.
+A branch may open with `if (condition)`, which runs it only when the condition holds, or with `else`, which runs it only when no sibling's condition held; a branch with neither always runs.
+
+```bpmnscript
+process expense-approval {
+ var amount: number
+
+ start ExpenseSubmitted
+
+ parallel {
+ if (amount > 10000) {
+ user AuditReview(assignee: "auditor")
+ }
+ else {
+ user SkipAudit(assignee: "clerk")
+ }
+ }
+
+ end ExpenseProcessed
+}
+```
+
+With no condition anywhere, the statement compiles to a parallel gateway pair.
+A condition on any branch turns both the fork and the join into inclusive gateways, and every unconditioned branch still runs beside whichever conditioned ones matched ([ADR-0031](../../docs/decisions/0031-inclusive-and-event-based-gateways.md)).
+When every branch is conditioned and none matches, the run continues past the join, through the `else` branch if there is one; a closing `else fail` stops the run instead.
+
+These combinations are errors:
+
+- an `else` branch beside a branch with no condition, since that branch always runs and the `else` never would,
+- a second `else` branch, or an `else` on a statement with no conditioned branch,
+- `else fail` on a statement with no conditioned branch, beside an unconditioned branch, or beside an `else` branch.
+
+### What `goto` can reach
+
+`goto X` jumps to the step named `X` in the same container: the process, a `subprocess` or `attempt` body, or a host-less handler's body, at any nesting depth of `if`, loop and `parallel` blocks within it.
+It never reaches into another process, into or out of a sub-process, or into or out of a host-less handler, which mirrors BPMN's rule that a sequence flow cannot cross a sub-process boundary.
+A `subprocess` is a target from its own container, and so is an `await` that carries a name, unless its trigger is `link`.
+An `on` handler has no name and is never a target.
+
+A hosted handler (`on Host: ...`) is the exception: its body shares the host's container, so a `goto` crosses freely between it and the main flow in both directions.
+A host-less handler written inside a hosted handler's body therefore guards the whole surrounding container, not just that body.
+
+A `goto` into a `parallel` or `await { }` branch from outside it is an error, since the token would leave the join waiting for branches the run never entered.
+A target across a boundary fails to resolve, and the message explains the boundary when the name exists elsewhere in the process:
+
+```text
+'X' is inside subprocess 'Y'
+ note: a goto cannot cross a subprocess boundary
+'X' is inside the 'on error(PAYMENT_FAILED)' handler
+ note: a goto cannot cross an event handler boundary
+ note: an event handler's steps run only when its event fires
+'X' is outside subprocess 'Y'
+ note: a boundary event attaches to an activity in its own scope
+```
+
+### Job settings on a gateway
+
+`if`, `while`, `do ... while`, `parallel`, and `await { }` each create a gateway that has no name of its own.
+Its [engine settings](#engine-settings) go in parens on the statement head, after the condition for `if` and the loops.
+`if`, `parallel`, and `await { }` also create a join, whose settings share the same parens with a `join` prefix: `joinAsyncBefore`, `joinAsyncAfter`, `joinExclusive`, `joinJobPriority`, `joinRetryCycle`.
+An `if` chain is one gateway however many `else if` branches it has, so an `else if` takes no parens of its own.
+
+```bpmnscript
+process order-fulfillment {
+ var amount: number
+
+ start OrderPlaced
+
+ if (amount > 10000) (asyncBefore: true, joinAsyncBefore: true, joinJobPriority: 5) {
+ user AuditReview(assignee: "auditor")
+ } else {
+ user SkipAudit(assignee: "clerk")
+ }
+
+ parallel (asyncBefore: true, exclusive: true, joinAsyncAfter: true) {
+ {
+ user PackItems
+ }
+ {
+ user PrintLabel
+ }
+ }
+
+ end OrderShipped
+}
+```
+
+A bare value in these parens is an error, and so is a `join` key on a loop, which has one gateway; the message names the plain spelling.
+`await { }` refuses `asyncAfter`, which the engine refuses on that gateway, so it goes on a branch's trigger instead.
+A `join` key on a statement whose branches all end their own path draws a warning, since the join is never reached.
+
+## Sub-processes, calls, and repetition
+
+### Sub-processes
+
+`subprocess X { }` groups steps into an embedded sub-process.
+Its body uses the same statements as a process body, including another `subprocess`, and a diagram shows it expanded with its steps inside.
+`attempt X { }` is the same container for work that can be given up, see [Giving a block of work up](#giving-a-block-of-work-up).
+
+### Call activities
+
+`call X(process: "") { }` starts another process and waits for it to finish ([ADR-0019](../../docs/decisions/0019-a-call-activitys-variable-mapping.md)).
+In the braces, `in target = source` passes a value into it and `out target = source` reads one back, the left side naming the variable in the receiving process; `in x` and `out x` copy a variable under its own name, and `in *` and `out *` copy every variable.
+`in local x = y` reads from or writes to variables of the call step itself rather than the whole process, which is mostly useful for imported diagrams.
+A mapping repeated within one direction is an error.
+
+`version: `, `binding: latest`, or `binding: deployment` picks the deployed version of the called process, never more than one.
+`businessKey: ""` sets the started instance's business key.
+
+`mapper: ""` or `mapperDelegate: "${bean}"` names an implementation of Operaton's `DelegateVariableMapping`, valued like `class` and `delegate` on a service task.
+It runs after the declared `in` and `out` mappings and adds to them.
+Writing both is an error, and a `call` carries no `field`, since the engine injects none into a mapper.
```bpmnscript
process order-handling {
@@ -375,33 +625,27 @@ process order-handling {
}
```
-#### Repetition
+A missing `process` and an unknown `binding` value are errors.
-A `for` clause after a statement's id, ahead of its parens, says how often the step runs.
-It is legal on `user`, `service`, `script`, `step`, `send`, `receive`, `decide`, `subprocess`, `attempt`, and `call`, and compiles to `bpmn:multiInstanceLoopCharacteristics`.
-`for`, `each`, `sequentially`, and `until` are reserved, so none of the four doubles as a plain name elsewhere in a process.
+### Repetition
-| Clause | Runs |
-| -------------------------- | ---------------------------------------------------------------------- |
-| `for each line in lines` | once per element of `lines`, each run seeing its own element as `line` |
-| `for each in lines` | once per element of `lines`, binding no element |
-| `for 3` | three times |
-| `for 3 each line in lines` | three times, run `n` still seeing element `n` of `lines` |
+A `for` clause between an activity's name and its parens runs it several times, as a multi-instance activity ([ADR-0022](../../docs/decisions/0022-repetition-the-for-clause-and-its-per-run-job-settings.md)).
-A literal count is a non-negative whole number, quoted or not; a bare name or a `"${...}"` expression is left to the engine, which reads a constant count as text with `Integer.parseInt` and truncates any other number with `intValue()` (`MultiInstanceActivityBehavior.resolveLoopCardinality`).
+| Clause | Runs |
+| -------------------------- | ------------------------------------------------------------------ |
+| `for each line in lines` | once per element of `lines`, each run seeing its element as `line` |
+| `for each in lines` | once per element of `lines`, binding no element |
+| `for 3` | three times |
+| `for 3 each line in lines` | three times, run `n` seeing element `n` of `lines` |
-A count and a collection are not alternatives.
-Writing both lets the count decide how many runs there are while each run still binds its element.
-A collection written as a plain name is the process variable of that name, and anything else is written as a quoted expression, so `for each line in "${order.lines}"` reads a property where `for each line in lines` reads a variable.
-An element name with no collection to take it from is a deployment error in Operaton, which is why the grammar offers one only inside `each ... in ...`.
+A literal count is a non-negative whole number, quoted or not, and a bare name or a `"${...}"` expression is left to the engine.
+A collection written as a plain name is the process variable of that name; anything else is a quoted expression, so `for each line in "${order.lines}"` reads a property.
-The runs happen at once, which is the engine's own default, unless `sequentially` orders them one after another.
-
-`until ( )` drops the runs still outstanding, once the condition holds.
-Operaton keeps `nrOfInstances`, `nrOfActiveInstances`, and `nrOfCompletedInstances` on the repetition as a whole, where every run's condition can read them, so those three are the names the condition can read.
-`loopCounter` is set on each run and is readable there too: in the run's body, its `input` parameters, and the `until` condition alike.
-A sequential repetition evaluates the condition on the run that just finished, since only one run is ever active (`SequentialMultiInstanceActivityBehavior.complete`); a parallel one evaluates it on whichever concurrent run just ended, not the whole set, so `loopCounter` there names that one run's index (`ParallelMultiInstanceActivityBehavior.concurrentChildExecutionEnded`).
-All four are in scope without a `var` declaration, as is the element name.
+The runs happen at once unless `sequentially` orders them one after another.
+`until (condition)` cancels the runs still outstanding once the condition holds.
+The condition can read `nrOfInstances`, `nrOfActiveInstances`, and `nrOfCompletedInstances`, kept for the repetition as a whole, and `loopCounter`, the index of the current run, which the run's body and its `input` parameters can read too.
+A sequential repetition checks the condition after each run; a parallel one checks it whenever any run ends, with `loopCounter` naming that run.
+These four and the element name need no `var`.
```bpmnscript
process invoice-batch {
@@ -416,11 +660,11 @@ process invoice-batch {
}
```
-`asyncBefore`, `asyncAfter`, `exclusive`, and `retryCycle` in a repeated step's settings put one job around the whole repetition rather than one job per run.
-`runAsyncBefore`, `runAsyncAfter`, `runExclusive`, and `runRetryCycle` put the matching job on each run instead, written in the same parens as the step's own settings.
-There is no `runJobPriority`: `jobPriority` prices the per-run job on its own, since `createActivityOnScope` reads it off the step regardless of what repeats around it; the whole-loop job takes the process's own priority, and no attribute writes one there.
-A `run*` key on a step with no `for` clause is an error, since one job per run means nothing where there is no run.
-`exclusive` or `retryCycle` needs `asyncBefore` or `asyncAfter` beside it for the whole-loop job, and `jobPriority`, `runExclusive`, or `runRetryCycle` needs `runAsyncBefore` or `runAsyncAfter` beside it for the per-run job, or the setting configures nothing (warning).
+On a repeated step, `asyncBefore`, `asyncAfter`, `exclusive`, and `retryCycle` configure one job around the whole repetition.
+`runAsyncBefore`, `runAsyncAfter`, `runExclusive`, and `runRetryCycle`, in the same parens, configure a job for each run instead.
+There is no `runJobPriority`: `jobPriority` already prices each run's job, and the whole-repetition job takes the process's priority.
+`runExclusive` and `runRetryCycle` need `runAsyncBefore` or `runAsyncAfter` beside them, and so does `jobPriority` on a repeated step, or they configure nothing and draw a warning.
+A `run*` key on a step without a `for` clause is an error.
```bpmnscript
process order-notifications {
@@ -430,148 +674,126 @@ process order-notifications {
}
```
-A repeated step cannot map an `output` parameter, because Operaton refuses to deploy that combination outright.
-An `input` parameter is fine.
-
-### Conditioning a parallel branch
-
-A `parallel` branch may open with `if (condition)`, with `else`, or with nothing at all.
-A branch with no head always runs, exactly like an ordinary `parallel` branch.
-A branch headed by `if (condition)` runs only when that condition holds.
-An `else` branch runs only when no condition on a sibling branch held.
+## Events
-The head decides the element for the whole statement, not just for its own branch.
-No condition anywhere on the statement compiles to the ordinary `bpmn:parallelGateway` fork and join.
-A condition on any one branch compiles both the fork and the join to `bpmn:inclusiveGateway` instead, and every unconditioned sibling still runs, alongside whichever conditioned branches also matched.
+### The event layer
-The compiler emits a fallback flow out of an inclusive fork only where Operaton can take it.
-The engine takes that flow when none of the fork's other flows were taken, so a fork with every branch conditioned and no fallback at all would still deploy, then stop with a stuck execution the first time nothing matches.
-Writing `else` gives the fallback a body to run before the join; leaving it out routes the fallback straight to the join when every branch carries a condition.
-A branch with no head is taken every time, so beside one no fallback is written at all.
+The event layer catches and raises BPMN events.
+An `on { }` handler is a catch block: it sits at the end of the body it guards, after the last statement, the way `catch` follows `try`, and it guards the process, a `subprocess` or `attempt` body, or another handler's body.
+A handler anywhere else, or before a statement of its body, is an error.
```bpmnscript
-process expense-approval {
- var amount: number
+process payment {
+ error PAYMENT_FAILED(message: "The payment failed")
+ var reason: string
- start ExpenseSubmitted
+ start Ordered
+ service Pay(class: "com.example.Pay")
+ end Paid
- parallel {
- if (amount > 10000) {
- user AuditReview(assignee: "auditor")
- }
- else {
- user SkipAudit(assignee: "clerk")
- }
+ on error(PAYMENT_FAILED, message: reason) {
+ user HandleFailure(assignee: "demo")
+ end Failed
}
-
- end ExpenseProcessed
}
```
-A headless branch beside an `else` is rejected: it runs every time, so the fork's flow set never comes out empty and the fallback behind the `else` never fires.
-A second `else` branch on one statement is rejected, and so is an `else` on a statement where no branch carries a condition, since with nothing conditioned every branch already runs and there is nothing left to fall back from.
+A catch binding pairs a field of the event (`code`, and for `error` also `message`) with the variable that receives it, like the `e` in `catch (Exception e)`.
+Leaving the code out, as in `on error { }`, catches any event of that kind.
+`alongside` makes a handler non-interrupting, so the guarded body keeps running beside it.
+
+`throw ` raises an event and ends the current path, and `emit ` raises it and continues.
+`emit link` is the one emit that ends its path, see [Link events](#link-events).
+
+An error or escalation code is declared at the top of the process body, beside the `var` declarations, as `error CODE(message: "text")` or `escalation CODE`, and every throw, catch, and [error mapping](#external-task-extras) names it ([ADR-0023](../../docs/decisions/0023-event-roots-from-usage-and-declared-codes.md)).
+`message` is the text a thrown error carries; an escalation has none.
+A code that isn't name-shaped goes on the declaration as `code: "..."`, so every use site is a plain name.
+
+| Trigger | Payload | `alongside`? | `throw` (ends the path) | `emit` (continues) |
+| -------------- | ------------------------------------------------------------- | ------------------------------ | ------------------------ | ------------------------------------ |
+| `error` | a declared code, optional `code: c` and `message: m` bindings | no, an error always interrupts | `throw error(CODE)` | none |
+| `escalation` | a declared code, optional `code: c` binding | yes | `throw escalation(CODE)` | `emit escalation(CODE)` |
+| `message` | a name | yes | `throw message("Name")` | `emit message("Name")` |
+| `signal` | a name | yes | `throw signal("Name")` | `emit signal("Name")` |
+| `timer` | a duration, or an `at` or `every` key and a time | yes | none | none |
+| `condition` | a condition | yes | none | none |
+| `compensation` | none | no, its scope already finished | `throw compensation` | `emit compensation` |
+| `cancel` | none | no, the block stops either way | none, `end X cancel` | none |
+| `link` | a name | no handler, only `await link` | none | `emit link("Name")`, ending the path |
+
+What each trigger means:
+
+- `error` and `escalation` are plain catch blocks.
+ An escalation only travels up within its own guarded scope.
+- `message` is received by correlation on its name, by a handler, a message start, an `await`, or a `receive` task.
+ `throw message` and `emit message` send one only when they carry a `class`, `expression`, `delegate`, or `topic` binding; without one the event only shows in the diagram, which draws a warning.
+ More than one binding is an error, and so is a binding on any other trigger.
+- `signal` is a broadcast: `emit signal("Name")` notifies every catch anywhere waiting on that name.
+- `timer` reads its form from the parens: `"PT1H"` is a duration, `at: "2026-08-01T09:00:00"` a fixed moment, `every: "R/PT10M"` a cycle, see [Timers](#timers).
+ The clock starts when the guarded scope starts, and an interrupting `every` fires once, since firing ends the scope, so it draws a warning; `alongside` keeps it firing.
+- `condition` is checked when the guarded scope starts, and again whenever a variable it reads changes.
+- `compensation` is a subprocess's undo block, see [Undoing finished work](#undoing-finished-work).
+- `cancel` gives up an `attempt` block, see [Giving a block of work up](#giving-a-block-of-work-up).
+- `link` is a jump drawn as two events, see [Link events](#link-events).
+
+Two handlers that register the same catch on one scope are an error; a handler inside a block and one attached to that block share the scope.
+So is an escalation catch-all beside a coded escalation catch on the same scope.
+
+### Timers
+
+A timer value has to fit its particle:
+
+- a duration (`after`, or a bare value) is an ISO 8601 duration such as `"PT8H"`, alone or beside a start or end date-time,
+- `at` is an ISO date-time or a period,
+- `every` is a repeat such as `"R3/PT10M"`, a six-field cron expression, or a nickname such as `"@daily"`.
+
+A value that doesn't fit is an error on a timer start, which the engine parses at deployment, and a warning everywhere else, since the engine reads it only once the scope is entered.
+An unknown particle is an error.
+A timer job setting written both on an `on timer` head and on its body's `start` is an error.
-### The event layer
+### Attaching a handler to one step
-An `on { }` handler is a catch block, sitting at the end of the body it guards, the way a catch block sits after its try body: `on error(PAYMENT_FAILED) { ... }`.
-That body is a process, a `subprocess` or `attempt` block, or another handler's body, since BPMN lets one event sub-process nest inside another.
-
-A binding beside the code in the parens is the caught value, the `e` in `catch (Exception e)`.
-It pairs a binding field (`code`, and for `error` also `message`) with the process variable that receives it: `on error(PAYMENT_FAILED, code: c, message: m) { ... }`.
-Omitting the code, as in `on error { }`, catches any event of that kind.
-
-`alongside` marks a handler non-interrupting, so the guarded scope's main flow keeps running beside it.
-
-Two verbs raise an event.
-`throw ` ends the current path right there, exactly like `throw` in a programming language, and `emit ` fires the event and keeps going.
-`emit link` is the one emit that ends its path instead, because the token continues at the catch of the same name, see [Link events](#link-events).
-
-Every error and escalation code is a declaration in the process header, `error CODE(message: "text")` or `escalation CODE`, that every throw, emit, and catch site names, as does an external task's `error when ` mapping (see [External task extras](#external-task-extras)).
-The declarations sit with the `var` declarations at the top of the body.
-`message:` is the text a thrown error of that code carries at runtime; BPMN gives an escalation none.
-A code that is not identifier-shaped goes on its declaration as `code: "..."`, so the use site is a bare name in every case.
-
-There are nine trigger kinds, and every one but `link` opens an `on` handler:
-
-| Trigger | Payload | `alongside`? | `throw` (ends the path) | `emit` (continues) |
-| -------------- | ------------------------------------------------------------- | ---------------------------------- | ----------------------------------- | ---------------------------------------- |
-| `error` | a declared code, optional `code: c` and `message: m` bindings | no, an error always interrupts | `throw error(CODE)` | none, an error ends its path |
-| `escalation` | a declared code, optional `code: c` binding | yes | `throw escalation(CODE)` | `emit escalation(CODE)` |
-| `message` | a name | yes | `throw message("Name")` | `emit message("Name")` |
-| `signal` | a name | yes | `throw signal("Name")` | `emit signal("Name")` |
-| `timer` | a duration, or an `at` or `every` key and a time | yes | none, it fires off the clock | none |
-| `condition` | a condition expression | yes | none, it fires off data | none |
-| `compensation` | none | no, its scope has already finished | `throw compensation` | `emit compensation` |
-| `cancel` | none | no, the block stops either way | none, an `end` carries it | none |
-| `link` | a name | no handler, only `await link` | none, a link continues at its catch | `emit link("Name")`, which ends the path |
-
-`timer` and `condition` are handler-only: nothing in the process raises them.
-`cancel` is carried on an `end` statement rather than raised by a verb, and it is the one kind with no host-less handler, since it is caught on the block it gives up.
-`link` has no handler at all: it is caught by an `await link` of the same name and by nothing else.
-The rest, message included, are both caught and raised, under the one rule above.
-
-Reading each kind:
-
-- `error` and `escalation` are the plain catch blocks.
- An error always interrupts the scope it guards, since BPMN has no non-interrupting error.
- An escalation may interrupt or, with `alongside`, run beside the main flow, and only ever travels up within its own guarded scope.
-- `message` is both received and sent.
- The handler and a message start event receive one by correlation, the engine's own mechanism, so either needs only the name.
- `emit message("Name")` and `throw message("Name")` send one.
- A `class`, `expression`, `delegate`, or `topic` setting is what makes the engine send it, four of the five bindings a `service` task takes.
- `type` is not among them, since a thrown message opens no member block for the fields a mail or shell task needs.
- Without one the event delivers nothing.
-- `signal` is a broadcast channel.
- `emit signal("Name")` notifies every listener anywhere waiting on that name and continues; `throw signal("Name")` broadcasts the same way and ends this path.
- Its reach is wider than an escalation's.
-- `timer` picks its BPMN form from what the parens carry: a bare `"PT1H"` is a duration, `at: "2026-08-01T09:00:00"` a fixed moment, `every: "R/PT10M"` a repeating cycle.
- The clock starts when the guarded scope starts.
- An interrupting `every` fires once, because the first firing ends the scope it's timing; `alongside` lets it keep firing.
-- `condition` reads like `if`: the expression is checked when the guarded scope starts, and again whenever a variable it reads changes.
-- `compensation` is a subprocess's undo block, the steps that reverse whatever the subprocess already finished.
- It runs when compensation reaches the subprocess, and only for an instance that actually completed, since one that never finished has nothing to undo.
- Two routes send it there: a `throw compensation` or `emit compensation` in an enclosing scope, and a cancel end giving up an `attempt` block the subprocess sits in.
- It carries no code, name, condition, or timer, there is at most one per subprocess, and it sits directly inside the `subprocess` or `attempt` body it undoes.
- A process has no completed enclosing scope to reverse, so `on compensation` at process level is rejected.
- `throw compensation` undoes the nearest enclosing scope's completed work newest first and ends the path; `emit compensation` runs the same undo, waits for it, and continues.
-- `cancel` gives up a whole block of work written with `attempt`.
- `end cancel` inside the block gives it up, `on : cancel` beside the block catches it, and the undo blocks of the finished steps run in between, see [Giving a block of work up](#giving-a-block-of-work-up).
-- `link` is a jump drawn as two events, the throwing `emit link` and the catching `await link`, paired by name, see [Link events](#link-events).
+`on : (...) { }` attaches a handler to one step as a boundary event, catching only while that step runs ([ADR-0027](../../docs/decisions/0027-boundary-events-attached-to-an-activity.md)).
+`on ReviewInvoice: timer("PT2H") { ... }` reads "if reviewing the invoice takes longer than two hours, do this instead".
+The colon tells a host from a trigger.
-### Attaching a handler to one step
+```bpmnscript
+process invoice-review {
+ start Received
+ user ReviewInvoice(assignee: "demo")
+ end Done
-Every trigger but `compensation` and `link` can name a single host step instead of guarding a whole body, and `cancel` is the one that has to.
-`on : (...) { }` attaches the handler to `` as a `bpmn:boundaryEvent`, catching only while that one step runs, so `on ReviewInvoice: timer("PT2H") { ... }` reads "if reviewing the invoice takes longer than two hours, do this instead" rather than "at any point in the process".
+ on ReviewInvoice: timer("PT2H") {
+ user Escalate(assignee: "manager")
+ goto Done
+ }
+}
+```
-The colon is what separates a host from a bare trigger.
-Trigger words are ordinary identifiers rather than keywords (see below), so a host-less handler carrying a code and a hosted handler carrying none would otherwise both read as `on` followed by two identifiers; the colon settles which reading applies at the second token.
+The host is an activity: a `user`, `service`, `script`, `step`, `send`, `receive`, or `decide` task, a `subprocess`, an `attempt` block, or a `call`.
+Anything else, an `await` included, is an error.
+An escalation attaches only to a `subprocess`, an `attempt`, a `call`, or a `user` task, and a cancel only to an `attempt`.
+Every trigger but `compensation` and `link` can attach, and `cancel` has to.
+`alongside` lets the host run on beside the handler; without it the host is cancelled when the trigger fires.
-A host has to be a step an engine token can be running at: a `user`, `service`, `script`, `send`, or `receive` task, a `step`, a `decide` step, a `subprocess`, an `attempt` block, or a `call`.
-A `start` or `end` event, a `goto`, a `throw` or `emit`, and another handler are all rejected, and so is an `await` of any trigger kind: `BpmnParse.parseBoundaryEvents` attaches to an activity alone, and an intermediate catch event is none.
-`escalation` narrows the set further, to a `subprocess`, an `attempt` block, a `call`, or a `user` task, matching Operaton's own restriction.
-`cancel` narrows it to one kind, an `attempt` block, the only host Operaton accepts a cancel boundary on.
-`alongside` keeps its usual meaning, letting the host run beside the catch instead of being canceled the moment the trigger fires, and `error` still always cancels its host.
+A hosted body ends where its last statement ends and never falls through to what follows the host, since a non-interrupting boundary would otherwise run the rest of the process twice.
+Rejoin the main flow with a `goto`, as above.
+A hosted body can't open with a `start`.
-A hosted handler's body is self-contained the way any `{ }` block is.
-It ends where its last statement ends and never falls back into whatever follows the host, because falling through by default would duplicate the token for a non-interrupting boundary and run the rest of the process twice.
-Rejoining is spelled out with a `goto`, which works in both directions, since the body's steps share the host's own container rather than living in one of their own.
-An explicit `start` cannot open a hosted body, unlike a host-less one: the body is entered from the boundary event, not from a container's entry point.
+### Undoing finished work
-To make a single step undoable rather than a whole subprocess, wrap that step in its own `subprocess` with an `on compensation` block.
-BPMN can also attach a compensation handler directly to one activity, through a boundary event plus a separate, normally dormant activity that only runs under compensation.
-`compensation` is the one trigger kind with no attached form here: wrapping in a `subprocess` already reaches the same granularity with a construct the language has, and BPMN's boundary mechanism needs that second dormant activity the language does not otherwise expose.
+`on compensation { }` inside a `subprocess` or `attempt` body is that sub-process's undo block, the steps that reverse what it finished ([ADR-0028](../../docs/decisions/0028-compensation-as-subprocess-undo-block.md)).
+It runs only for an instance that completed, in two cases: a `throw compensation` or `emit compensation` in an enclosing scope, or a cancel end giving up an `attempt` block the subprocess sits in.
+`throw compensation` undoes the enclosing scope's completed work newest first and ends the path; `emit compensation` waits for the undo and continues.
-An undo block sees the subprocess's variables as they stood when it completed, so anything changed by whatever ran afterward is invisible to the steps reversing it.
-Operaton does not carry compensation across the separate process instance a `call` starts, so a called process has to compensate its own work.
+A sub-process has at most one undo block, it carries no payload, and `on compensation` at process level is an error, since a process has no completed scope to reverse.
+To make one step undoable, wrap it in its own `subprocess` with an undo block; compensation has no hosted form.
+An undo block sees the subprocess's variables as they were when it completed.
+Operaton doesn't carry compensation into the process a `call` starts, so a called process compensates its own work.
### Awaiting an event inline
-`await ()` is a statement on the main flow rather than a catch block, and it blocks instead of firing.
-Written where any other step would go, as in `await message("Invoice Received")`, the token stops there until the trigger fires and then falls through to whatever follows, exactly like a `bpmn:intermediateCatchEvent`.
-An `on` handler races its trigger against the rest of the guarded body and fires only if the trigger wins; a plain `await` sets nothing against its trigger and blocks until it fires.
-[`await` with several branches](#waiting-on-several-triggers-at-once) races its own branches against each other instead.
-
-Five trigger kinds can be awaited: `message`, `timer`, `signal`, and `condition` use the same payload surfaces `on` and a boundary event already use, and `link` has no other surface and gets [its own section](#link-events).
+`await ()` is a step on the main flow: the path stops until the event arrives, then continues with the next statement.
```bpmnscript
process invoice-intake {
@@ -584,18 +806,15 @@ process invoice-intake {
}
```
-`error`, `escalation`, `compensation`, and `cancel` have no awaited form: an error or escalation is raised and caught by a racing handler rather than blocked on, compensation is invoked by the engine's compensation machinery, and a cancel is written on the `end` that gives an `attempt` block up.
-Writing one of the first three after `await` is rejected with a diagnostic naming the five legal words, and `await cancel` draws its own, pointing at the `end cancel` that gives a block up and the `on : cancel` that catches it.
-
-A plain `await` takes no host, no catch bindings, no `alongside`, and no body.
-An optional name between the trigger and the payload, `await message Paid("Paid")`, makes it a step a `goto` can target, under the same duplicate-name rules as any other step; without one the id is synthesized (`Catch_`).
-[ADR-0026](../../docs/decisions/0026-intermediate-catch-events.md) covers why `await` beat `wait` and `receive`, and [ADR-0030](../../docs/decisions/0030-link-events-for-import-round-trip-symmetry.md) why every `await` can carry a name and why `link` joined the trigger scope.
+The awaitable triggers are `message`, `timer`, `signal`, `condition`, and [`link`](#link-events), with the same payloads as on `on`.
+`await error`, `await escalation`, and `await compensation` are errors naming the legal words, and `await cancel` points at `end X cancel` and `on X: cancel` instead.
+An `await` takes no host, binding, `alongside`, or body.
+An optional name between the trigger and the payload, `await message Paid("Paid")`, makes it a `goto` target ([ADR-0026](../../docs/decisions/0026-intermediate-catch-events.md)).
### Link events
-A link is a jump drawn as two events with no sequence flow between them, BPMN's off-page connector.
-`emit link` is the throwing end, `await link` the catching end, and the quoted link name is what pairs them.
-Both ends carry the link name as their diagram label.
+A link is a jump drawn as two events with no flow between them, a diagram's off-page connector.
+`emit link` throws, `await link` catches, and the quoted link name, also their diagram label, pairs them.
```bpmnscript
process invoice-rework {
@@ -614,22 +833,20 @@ process invoice-rework {
}
```
-`emit link` ends its path the way a `goto` does: the token continues at the `await link` of the same name and nowhere else, so a step written after it can never run.
-Nothing flows into a link catch, so the statement before an `await link` has to end the path: an `end`, a `throw`, a `goto`, an `emit link`, or a block whose every branch does one of those.
-One `await link` per name in the whole file, at any depth, and any number of `emit link` may name it.
-Both ends sit in one container, the process, subprocess, or handler body, the same rule a `goto` follows, and an `emit link` cannot reach into a `parallel` or multi-branch `await` branch from outside it, since a token arriving inside one branch leaves the block's join waiting for the branches the run never entered, so it never completes.
-`link` cannot head a branch of a multi-branch `await`, because Operaton refuses a link catch behind an event-based gateway.
-An engine setting or a listener on `emit link` is an error: the engine creates no activity for a link throw, so nothing written there would run; the same items on `await link` are fine.
-An `await link` nothing emits is a warning rather than an error, since the engine deploys it and an imported diagram may carry one.
+`emit link` ends its path like a `goto`, so nothing written after it runs.
+Nothing flows into a link catch, so the statement before an `await link` has to end the path: an `end`, a `throw`, a `goto`, an `emit link`, or a block whose every branch does.
+A name has one `await link` in the whole file and any number of `emit link`.
+Both ends sit in one container, as with `goto`, and an `emit link` can't reach into a `parallel` or `await { }` branch from outside it.
-`goto` stays the way to jump in source: its target is scoped to its container and needs no file-wide name, and it compiles to the one sequence flow it prints as.
-`link` exists for a diagram that already carries one, so that it imports and compiles back to the same two events; [ADR-0030](../../docs/decisions/0030-link-events-for-import-round-trip-symmetry.md) makes that argument.
+These are errors: an `emit link` with no catch, a `throw link`, a `goto` onto a link catch, `link` heading a branch of `await { }`, and an engine setting or listener on `emit link`, where the engine creates nothing to run it.
+An `await link` that nothing emits is a warning, since an imported diagram may carry one.
+Write `goto` to jump in your own source; `link` exists so that a diagram carrying one imports and compiles back to the same two events ([ADR-0030](../../docs/decisions/0030-link-events-for-import-round-trip-symmetry.md)).
### Waiting on several triggers at once
-`await { ... }` with two or more branches compiles to a `bpmn:eventBasedGateway` with one `bpmn:intermediateCatchEvent` per branch, waiting on every trigger at once and continuing down whichever fires first.
-Two branches are the minimum; write a single `await ()` instead when there is only one.
-Each branch opens the same way a plain `await` does: a trigger word, its payload and settings, then a body the plain form has no place for; `link` is the one awaitable kind a branch cannot head, and a branch carries no name.
+`await { }` with two or more branches waits on every trigger at once and continues down whichever fires first, as an event-based gateway.
+Each branch is a trigger, its payload and settings, and a body; it carries no name, and `link` can't head one.
+For a single trigger, write a plain `await`.
```bpmnscript
process order-fulfillment {
@@ -644,13 +861,13 @@ process order-fulfillment {
}
```
-Exactly one branch of the pair above ever runs.
-Operaton starts every catch behind this gateway with a start behavior that cancels its siblings the moment one of them fires, so whichever of `ShipOrder` or `ChaseCustomer` goes first is the only one that does.
-A `condition` branch is the one exception to "waits": its expression is checked the moment the statement is reached, so a condition already true wins immediately, without the gateway waiting on anything at all.
+Exactly one branch runs: when one trigger fires, the engine cancels the others.
+A `condition` branch is checked as soon as the statement is reached, so a condition that already holds wins at once.
+Two branches waiting on the same message or signal name are an error.
### Starting on an event
-A process's own start may carry a trigger, the same clause `on` and `await` already use: a soft trigger word followed by its payload.
+A process's own `start` can carry a trigger: `message`, `signal`, `timer`, or `condition`, with the payload it takes elsewhere.
```bpmnscript
process order-intake {
@@ -658,20 +875,17 @@ process order-intake {
user ConfirmOrder(label: "Confirm the order", assignee: "demo")
- emit message NotifyWarehouse("WarehouseNotified")
+ emit message NotifyWarehouse("WarehouseNotified", class: "com.example.demo.LogDelegate")
- throw message OrderAcknowledged("OrderAcknowledged")
+ throw message OrderAcknowledged("OrderAcknowledged", class: "com.example.demo.LogDelegate")
}
```
-Four words are legal there: `message`, `signal`, `timer`, and `condition`, each with the payload it already carries elsewhere, a name for the first two, a duration or an `at` or `every` key for the third, and the condition expression, the same clause `on condition` and `await condition` carry, for the fourth.
-A subprocess start and an event-handler start take none, because both are entered by their container rather than by an event of their own; the validator rejects a trigger written on either.
-Neither takes `initiator` or a `form` block: `BpmnParse.parseScopeStartEvent` reads neither off a start that is not the process's own, so the validator rejects both there too.
-A message start's name has to be a fixed one: an expression anywhere in it is rejected, whether it opens the name as a raw template or sits further in and leaves the name a plain string, since a process that has not started yet has no variables for the engine to evaluate it against.
-
-Writing `error`, `escalation`, or `compensation` on a process start is rejected too, for a different reason: Operaton's own start-event parser does not branch on those three, so the engine ignores the trigger and starts the process exactly as if none were written, and this surface refuses to compile XML the engine would disregard.
+A message start's name has to be fixed text, since a process that hasn't started has no variables to evaluate an expression against.
+`error`, `escalation`, and `compensation` on a process start are errors, because the engine would ignore them and start the process as if no trigger were written.
+A start inside a subprocess, an attempt block, or a handler body takes no trigger, `initiator`, or `form`, since its container enters it.
-A process may carry more than one `start`, written as flat siblings, so one process is entered by hand and by a correlated message alike.
+A process can have several starts, so one process is started by hand and by a message alike:
```bpmnscript
process support-ticket {
@@ -684,20 +898,22 @@ process support-ticket {
}
```
-A `start` opens a chain and takes no incoming flow, so it sits first, right after another `start`, or after a statement that always ends or redirects the flow, such as an `end`, a `throw`, or a `goto`.
-Starts written back to back share the chain that follows, which is how `ByAgent` and `ByEmail` both enter `Triage`, and a start after an `end` opens a chain of its own that reaches a shared step by `goto`.
-A start after a step whose flow is still live is an error, since the page would not say whether that flow runs past the start or stops at it.
-A subprocess, an `attempt` block, and an event-handler body keep exactly one start, because Operaton's `BpmnParse.parseScopeStartEvent` rejects a second start on any scope that is not a process.
-A process keeps one plain or timer start, because `BpmnParse.selectInitial` rejects a second, and one message or signal start per name and one condition start per condition, because `BpmnParse.addEventSubscriptionDeclaration` rejects a repeat; the validator refuses each of those before the engine does.
-A body that does not open with a `start` gets a plain start of its own from the compiler, and that one is in the count: a plain or timer `start` further down such a body is the second one, so it needs a message, signal, or condition trigger, or has to open the body itself.
+A `start` takes no incoming flow, so it sits first, after another `start`, or after a statement that ends or redirects the flow, such as an `end`, a `throw`, or a `goto`.
+Starts written back to back share the chain that follows, and a start after an `end` opens its own chain, which reaches shared steps by `goto`.
+A start after a step whose flow still runs on is an error.
-Two warnings follow from how the engine picks a default start.
-A process whose starts are all message, signal, or condition starts has no default, so the engine can create an instance only by triggering one of them, and starting it by key fails at runtime.
-The engine offers a start form only on the default start, the plain or timer one, so a `form` block on any other start is parsed and never shown.
+The engine limits how many starts a scope has, and each limit is an error:
+
+- A subprocess, attempt block, or handler body has exactly one start, written first.
+- A process has one plain or timer start, one message or signal start per name, and one condition start per condition.
+- A body that doesn't open with a `start` gets a plain one from the compiler, which counts, so a plain or timer start further down is a second one.
+
+A process whose starts all carry a message, signal, or condition trigger can't be started by key, so it draws a warning.
+The engine shows a start form only on the plain or timer start, so a `form` on any other start draws a warning too.
### Ending every path
-`end terminate` stops every running path of its own scope at once, rather than raising something another handler could catch, which is why it sits on `end` instead of on `throw` and why it keeps the label a diagram's terminate node deserves, where a throw drops the label.
+`end X terminate` stops every running path in its scope at once ([ADR-0025](../../docs/decisions/0025-events-at-the-process-boundary.md)).
```bpmnscript
process stock-alert {
@@ -717,20 +933,14 @@ process stock-alert {
}
```
-A branch that reaches `terminate` never rejoins the fork it came from, so the join can end up with a single incoming flow from the branch that fell through instead, which Operaton runs as a plain pass-through rather than a wait.
-`terminate` is one of the two words an end carries rather than raises, and `cancel` is the other, see [Giving a block of work up](#giving-a-block-of-work-up).
+A branch ending in `terminate` never reaches the join, so the join waits only for the branches that do.
+`terminate` and `cancel` are the two triggers an `end` carries; any other is an error, since every other kind is raised with `throw`.
### Giving a block of work up
-`attempt X { }` is a block of work that can be given up as a unit.
-It is the `subprocess` statement under a second head, so it nests, takes a label, a repeat clause, settings, and every handler a subprocess takes.
-Three pieces make one construct: the block, an `end cancel` inside it that gives the block up, and an `on : cancel { }` beside it that says what happens next.
-Neither cancel piece is usable without the block.
-
-A cancel end gives up the block it sits in, and "in" means the container rather than the nearest braces.
-An `if`, a `while`, a `do`, a `parallel` branch, or an `await` branch inside the block is still the block, and so is the body of a handler attached to one of the block's steps, which shares its host's container.
-A nested `subprocess`, a host-less handler, and the process itself are containers of their own, so a cancel end written in one of those is rejected.
-The handler attaches to the block by name rather than opening on its own, which is why a host-less `on cancel` is rejected too: BPMN has no cancel start event for one to open on.
+`attempt X { }` is a block of work that can be given up as a unit ([ADR-0029](../../docs/decisions/0029-work-that-can-be-given-up.md)).
+It is a `subprocess` under another keyword, so it nests and takes a label, a repetition, settings, and handlers.
+Inside it, `end X cancel` gives the block up, and beside it, `on X: cancel { }` says what happens next.
```bpmnscript
process seat-booking {
@@ -766,132 +976,52 @@ process seat-booking {
}
```
-Giving the block up runs the undo blocks of the steps inside it that had already finished, newest first, and only when those have run does the flow reach the handler.
-`HoldSeat` carries an `on compensation` block, so the seat is back on sale before the customer hears the apology.
-`ChargeCard` carries none, so it stays completed and nothing reverses it.
-A block whose finished steps carry no undo block has nothing to undo and goes straight to the handler.
+Giving the block up runs the undo blocks of the steps inside it that had finished, newest first, then the handler.
+Here `HoldSeat` has an undo block, so the seat is released before the apology; `ChargeCard` has none, so nothing reverses it.
+An enclosing scope keeps whatever it finished before the block started.
+An `attempt` is not a database transaction: a charge taken or a message sent is reversed only by the undo blocks you write.
-The undo reaches the block's own finished steps and nothing else.
-An enclosing scope keeps whatever it had finished before the block started.
-An `attempt` is not a transaction in the database sense: Operaton runs a `bpmn:transaction` through the very behavior class it gives an ordinary sub-process, so a charge already taken or a warehouse already told is reversed only by the undo blocks the author wrote.
+A cancel end gives up the block whose container it is in.
+An `if`, a loop, a `parallel` or `await` branch inside the block, and a handler attached to one of its steps are still the block; a nested `subprocess`, a host-less handler, and the process are not, so a cancel end there is an error.
+A host-less `on cancel` is an error, and so is a cancel handler on anything but an `attempt`.
-A cancel end whose block carries no handler deploys and then stops with an error the first time a run reaches that end, because parsing the handler is what wires the two together.
-That is why writing one half of the pair without the other is a warning rather than an error, in both directions: a cancel handler on a block nothing inside gives up is a path no run can take.
-A block carrying neither half draws no diagnostic: an `attempt` with no cancel anywhere is an ordinary block of work that happens to serialize as `bpmn:transaction`, which is what lets an imported one round-trip unchanged.
+A cancel end in a block with no cancel handler deploys and then fails when a run reaches it, and a cancel handler on a block nothing gives up can never run, so either half without the other draws a warning.
+An `attempt` with neither is an ordinary block of work.
-`attempt` is a keyword like every other statement head, so the word cannot name anything else in a process; `cancel` is an ordinary identifier, like the other trigger words.
+## Reserved words
-### Contextual words
+These words are keywords and can't be used as a plain name; write a step's name in backticks and a variable as `"${...}"`:
-Only `on`, `throw`, `emit`, `alongside`, and `await` are reserved keywords in the event layer.
-The trigger kinds, the timer particles `after`/`at`/`every`, the field names `code`/`message`, the form field type `enum`, the member directions `input`/`output`/`field`/`property`, and the `when` of an error mapping are deliberately ordinary identifiers, so `var message: string`, `var enum: string`, `var timer: number`, and a task named `every` all parse like any other identifier.
-The `error` heading a mapping is the same soft trigger word every code site writes.
-They're among the most common variable and property names a Java-background author reaches for, which is why they stay available.
-The editor still highlights and completes them, but only in the positions where they carry event meaning.
+`alongside` `any` `attempt` `await` `boolean` `call` `date` `decide` `do` `each` `else` `emit` `end` `false` `for` `form` `goto` `if` `in` `json` `local` `null` `number` `on` `out` `parallel` `process` `receive` `script` `send` `sequentially` `service` `start` `step` `string` `subprocess` `throw` `true` `until` `user` `var` `while`
-### Job settings on a gateway
-
-An `if`, a `while`, a `do...while`, a `parallel`, and a multi-branch `await` each synthesize a gateway with no name to hang a setting on.
-Its five settings sit in a parens on the statement head instead, right where an ordinary element's settings sit.
-`if`, `parallel`, and a multi-branch `await` also synthesize a join beside the split, and the join's settings share the same parens under a `join`-prefixed spelling: `joinAsyncBefore`, `joinAsyncAfter`, `joinExclusive`, `joinJobPriority`, `joinRetryCycle`.
-An `if` chain lowers to one exclusive-gateway split no matter how many `else if` branches it carries, so the head parens govern the whole chain and an `else if` head takes none of its own.
-
-```bpmnscript
-process order-fulfillment {
- var amount: number
-
- start OrderPlaced
-
- if (amount > 10000) (asyncBefore: true, joinAsyncBefore: true, joinJobPriority: 5) {
- user AuditReview(assignee: "auditor")
- } else {
- user SkipAudit(assignee: "clerk")
- }
-
- parallel (asyncBefore: true, exclusive: true, joinAsyncAfter: true) {
- {
- user PackItems
- }
- {
- user PrintLabel
- }
- }
-
- end OrderShipped
-}
-```
-
-A `while` or a `do...while` has one gateway, so a `join`-prefixed key on either is an error naming the plain spelling to write instead.
-A multi-branch `await` head refuses `asyncAfter`: `BpmnParse.parseEventBasedGateway` refuses the flag on the gateway it deploys, so the setting has to move onto whichever branch trigger should carry it.
-A `join`-prefixed setting on a statement whose branches all end their own path is a warning rather than an error, since the join it would set is never reached.
-
-### Expressions
-
-Condition expressions are parsed as a real AST over the JUEL native subset: integer, decimal, string, boolean, and null literals; variable references with dot-property and index accessors; unary `!` and `-`; binary arithmetic and comparison; logical `&&` and `||`; the ternary `? :`; and parentheses.
-Anything outside that subset uses the quoted raw fallback, `"${...}"` or `"#{...}"`, carried as written.
-Both openers are the ones the engine evaluates, and a raw template is read with the same escapes as a string literal, so `"${fn(\"a\")}"` is the expression `${fn("a")}`.
-`on condition(...)` reuses the same grammar, so a variable read inside it goes through the same undeclared-variable and type checks as one read inside an `if`.
+Everything else is an ordinary name that has a special meaning only in position: the trigger words, `terminate`, `fail`, the timer particles `after`, `at`, and `every`, the binding fields `code` and `message`, the form type `enum`, the member words `input`, `output`, `field`, and `property`, `when`, every setting key, and every listener event but `start` and `end`.
+So `var message: string`, `var timer: number`, and a step named `every` are all legal, and the editor highlights and completes these words only where they carry meaning.
+Using a reserved word as a name, as in `if (date > deadline)`, is an error that names the word and suggests the `"${...}"` form.
## Diagnostics
-Validation beyond syntax lives in `src/bpmn-script-validator.ts`, which is the source of truth for the exact rules and their wording.
-The categories it covers:
-
-- Variables: an undeclared reference (warning), a type mismatch against the declared `var`, a name declared twice, a JUEL keyword or a hyphen in a name a rendered expression carries, a JUEL keyword read as a property inside a `"${...}"` template (`"${order.and}"`, outside its string literals), a condition whose static type is not boolean, and a composite `"${...} ${...}"` template under an operator.
- The reserved words are `empty`, `div`, `mod`, `not`, `and`, `or`, `le`, `lt`, `eq`, `ne`, `ge`, `gt`, and `instanceof`; the literal words, reserved the same way, are `true`, `false`, and `null`.
-- Tasks: a duplicate attribute key, a `service`, `send`, or `decide` task without exactly one binding attribute, a binding value in the wrong shape (quoted text under `expression`, `delegate`, or `mapperDelegate`, a template under `class` or `mapper`, an empty `class`, `expression`, `delegate`, `mapper`, `mapperDelegate`, `topic`, `decision`, or `process`), a `resultVariable` beside a `class` or `delegate` binding, which the engine refuses to deploy, or beside `topic` or `type`, which nothing writes (warning), a `mapDecisionResult` outside the four result mappings or without a `resultVariable` to map into (warning), `binding`, `version`, or `mapDecisionResult` on a `decide` step with no `decision`, a `script` task with an unsupported fence tag or an empty or unterminated body.
- A user task adds its own: a `priority` that is neither an integer nor a `"${...}"` expression, and a `dueDate` or `followUpDate` constant that is neither a `P...` period nor an ISO date-time.
- A `version` on a `formRef`, a `call`, or a `decide` step that is not a positive whole number or an expression is refused on all three alike.
- An external task's extras add their own: a `taskPriority` or an `error ... when` mapping on a step not bound with `topic`, a mapping headed by a word other than `error` or missing `when`, a mapping naming an undeclared code, and a `taskPriority` or `jobPriority` that is neither an integer nor a `"${...}"` expression.
- A `service`, `send`, or `decide` task bound with `type` adds its own: a required field its type's own parse requires missing, a field name its behaviour class does not declare, and, on a shell task, a field carried as an expression or a flag other than `true`/`false`.
-- Settings: a key the element does not own, a value in a shape its lowering cannot read (a quoted `asyncBefore`, an unquoted `retryCycle`), a `retryCycle` the engine's retry parser cannot read, which is dropped rather than refused (warning), a `for` clause's count that is not a non-negative whole number, a variable, or an expression yielding one, a `form` block on an element that renders none, a process header carrying a key it does not own, and an unkeyed value in the parens of an element with no payload to read it as (a task, a call, a subprocess, a listener, the process header, or a `start` or `end` with no trigger, where `start S("PT30M")` is a timer payload missing its `timer` word).
- A process header adds its own, since the engine stores every header value as written: a `historyTimeToLive` outside `PD` or ``, a `versionTag` that is not a quoted string or runs past 64 characters, a `"${...}"` template anywhere in `candidateStarterUsers` or `candidateStarterGroups`, an `isStartableInTasklist` that is not an unquoted boolean, and a `label` or `documentation` that is not a quoted string.
- A gateway statement's parens add their own: a bare value rather than a `key: value` setting, a `join`-prefixed key on a `while` or `do...while` loop, and `asyncAfter` on a multi-branch `await` head.
- A `join`-prefixed key on a statement whose branches all terminate warns, since the join it would set is pruned.
- A `run*` key on a step with no `for` clause, and `runJobPriority`, which does not exist, since the engine reads a job priority off the step alone.
- `exclusive`, `jobPriority`, or `retryCycle`, plain, `join`-, or `run`-prefixed, without the matching `asyncBefore`/`asyncAfter` beside it configures no job (warning); a timer carrier is exempt, since the timer itself creates the job, and a signal start, an `await signal`, or a signal race branch is exempt for `jobPriority`, which prices its subscription job (a boundary or handler signal catch declares none and keeps the warning).
-- Parameters: a direction word the owner doesn't take, a parameter on an element that carries none, a name repeated within one direction, an `output` mapping on a repeated step, an empty or blank string as a value, a list item, or a map entry's value, which the engine trims and reads as no value at all rather than as an empty string (warning), and the same fence rules a `script` task's body follows on a fenced script anywhere in a value, a list, or a map, since the engine resolves that tag only when the parameter is first evaluated.
- A `field` also errors on a kind that takes none, when its binding is anything other than `class`, `delegate`, or `type`, when its value is neither a quoted string nor a `"${...}"` expression, when it is empty, which deploys as neither a fixed value nor an expression, and when its quoted string opens with an escaped `\${` or `#{`, which has no fixed-text slot.
- A `property` line errors the same way on a kind that takes none and on a `service`, `send`, or `decide` step not bound with `topic`.
-- Listeners: an event word the element does not have, a binding count other than one, a missing timer on `on timeout` or a timer on any other event, a repeated event on one element, and the same fence rules a `script` body follows.
-- Structure: an empty process, subprocess, or handler body, an empty branch (warning), an empty loop body, which would drop the loop and its condition, a `do` body that always ends or redirects the flow, which would leave the loop gateway with no incoming flow, a parameter or listener written inside a body rather than in an element's attribute block, an unreachable statement, a process-level `start` after a step whose flow still runs on, a `start` anywhere but first in its subprocess, attempt block, or handler body, a second plain or timer start on a process, counting the plain start the compiler adds to a body that does not open with a `start`, a second message, signal, or condition start repeating an earlier one's payload, `initiator` or a `form` block on a start inside a subprocess, attempt block, or handler body, a process with several starts and no plain or timer one among them (warning), a `form` block on a start that is not the default one (warning), a `goto` reaching into a `parallel` or `await` branch from outside it, a second `else` branch on a `parallel` statement, an `else` branch with no conditioned sibling, and an `else` branch beside a sibling carrying no condition.
-- Names: a reused process name, step name, or `label`, a step name equal to the process id, which the compiled document can hold only once, and a name matching a synthesized-id pattern, the desugarer's own or the layouter's `_di`, `BPMNDiagram_`, and `BPMNPlane_` ids ([ADR-0010](../../docs/decisions/0010-deterministic-synthesized-ids.md)).
-- Call activities: a missing `process`, an unknown `binding` value, `binding` and `version` together, `mapper` and `mapperDelegate` together, and duplicate `in` or `out` mappings.
- A `decide` step pins its decision table with `binding` and `version`, under those same two rules.
-- Form fields: a type outside the five, a repeated field id, a field typed against a `var` of its name, a settings key outside the seven constraints and `pattern`, a constraint on a type its validator refuses or a `pattern` off a `date` field, a value in a shape the engine cannot parse (`required: false`, a bound that is not an integer, an empty `pattern` or `validator`, a `pattern` holding a letter `SimpleDateFormat` does not read), a literal default that is not what its type converts (`number`, not an integer; `boolean`, not `true` or `false`; `date` with no `pattern`, an ISO date rather than the engine's own `dd/MM/yyyy`), a value line on a field that is not an `enum`, an `enum` offering no values (warning), a repeated value id, a literal default naming none of the values, a block member that is not a `property` line, and a property value that is neither a quoted string nor a `"${...}"` expression.
-- Form references: `formKey` beside `formRef` on a user task, a `formRef` with neither `binding` nor `version`, and `binding` or `version` with no `formRef` to pin, under the same `binding`/`version` exclusivity a `call` and a `decide` step already use.
-- Events: a trigger word outside the set its verb accepts, a payload that doesn't match its trigger's shape, a handler in the wrong container or not at the end of its body, `alongside` on `error`, `compensation`, or `cancel`, two handlers registering one catch on one engine scope (a handler inside a block and one attached to that block share it), an escalation catch-all beside a coded catch of its own kind, two branches of one `await` block on one message or signal name, a timer job setting written on both an `on timer` head and its body's start, a host that isn't an activity a token can sit at, a binding attribute on a `throw` or `emit` whose trigger is not `message`, and more than one binding on one whose trigger is.
- A link pair adds its own: an `await link` after a statement whose flow still runs on, an `emit link` with no catch of its name, a second `await link` of one name anywhere in the file, a pair split across containers, an `emit link` reaching into a `parallel` or `await` branch from outside, `link` heading a race branch, a `goto` onto a link catch, an engine setting or listener on `emit link`, a `throw link`, and an `await link` nothing emits (warning).
-- The cancel construct: a cancel end outside an `attempt` block, a cancel handler with no host or on a host that is not one, and either half of the pair written without the other (warning).
-- Timers: an unknown particle, and a value that does not fit its particle's shape (`after` an ISO 8601 duration on its own or beside a start or end date-time, `at` a period or an ISO date-time, `every` an `R/...` repeat, a six-field cron, or a cron nickname such as `@daily`): an error on a timer start, which the engine parses at deployment, and a warning on every other carrier (an awaited timer, a race branch, an `on` handler, a timeout listener), which reads it only once its scope is entered; plus a repeating `every` on an interrupting handler (warning).
-
-Diagnostics name the valid alternative rather than reporting an unknown identifier, so `emit error` points at `throw error` and `binding = version` points at `version = `.
-
-## What `goto` can reach
-
-A custom `ScopeProvider` (`src/bpmn-script-scope-provider.ts`) resolves `goto` targets, and a hosted handler's `host` reference, against the steps of their own nearest enclosing container: the `process`, the `subprocess`, or the host-less `on` handler body they sit in, at any block-nesting depth within it.
-
-A `goto` therefore never resolves into another process, into a sibling or nested `subprocess`, into or out of a host-less handler's body, or out to a parent container, even when both are declared in the same file.
-A `subprocess` statement is itself a valid target, resolved from its own container like any other step, and so is an `await` that carries a name, unless its trigger is `link`: a link catch is entered by `emit link` of the same name and by nothing else.
-An `on` handler has no name, so it's never a target.
-This mirrors BPMN's rule that a sequence flow cannot cross a sub-process boundary, and a host-less handler is a kind of sub-process: its steps only run once its event fires.
-
-A hosted handler is the one exception.
-Its body is not a container of its own, so the container walk skips past it and a `goto` crosses freely in both directions between the body and the main flow, which is also how the handler's `host` reference resolves.
-One consequence is easy to miss while authoring: a host-less handler written inside a hosted handler's body guards the whole surrounding container, not just that escape path.
-
-A cross-boundary `goto` or an out-of-scope `host` fails to resolve, and a custom `Linker` (`src/bpmn-script-linker.ts`) replaces Langium's generic "could not resolve reference" with a boundary explanation whenever the name exists elsewhere in the process:
-
-```text
-'X' is inside subprocess 'Y'; a goto cannot cross a sub-process boundary.
-'X' is inside the 'on error(PAYMENT_FAILED)' handler; a goto cannot cross an event handler boundary: an event handler's steps run only when its event fires.
-'X' is outside subprocess 'Y'; a boundary event attaches to an activity in its own scope.
-```
-
-A handler is named by its header, since it has no name of its own.
-When the name exists nowhere at all, the generic message is left alone.
-
-Using a reserved keyword where an identifier belongs, as in `if (date > deadline)`, is caught by a custom `ParserErrorMessageProvider` (`src/bpmn-script-parser-error-message-provider.ts`), which names the offending word and points at the quoted `"${...}"` fallback instead of surfacing Chevrotain's token-mismatch message.
+The validator reports errors, which stop `build`, and warnings, which don't.
+A message names the problem and, where it can, the fix: `emit error` points at `throw error`, and an unknown key names the element it is not valid on.
+Most rules mirror a check Operaton makes when it deploys or runs a process, so the mistake shows in the editor instead of in the engine ([ADR-0013](../../docs/decisions/0013-validator-mirrors-parse-time-rules.md)); [`src/bpmn-script-validator.ts`](src/bpmn-script-validator.ts) holds the exact rules and wording.
+
+Each rule is described with the construct it governs:
+
+| Area | Where |
+| ------------------------------------------ | -------------------------------------------------------------- |
+| names and labels | [Names and labels](#names-and-labels) |
+| variables, JUEL words, and condition types | [Variables](#variables), [Expressions](#expressions) |
+| empty bodies, unreachable steps | [Statements](#statements) |
+| header values | [The process header](#the-process-header) |
+| tasks, bindings, and forms | [Tasks](#tasks) |
+| keys, engine settings, and unkeyed values | [Engine settings](#engine-settings) |
+| parameters, fields, properties, listeners | [What an element carries](#what-an-element-carries) |
+| `else fail`, parallel branches, `goto` | [Control flow](#control-flow) |
+| gateway settings | [Job settings on a gateway](#job-settings-on-a-gateway) |
+| calls and repetition | [Call activities](#call-activities), [Repetition](#repetition) |
+| triggers, handlers, timers, starts, links | [Events](#events) |
+| reserved words | [Reserved words](#reserved-words) |
+
+A trigger word outside the set its verb accepts, or a payload that doesn't fit its trigger, is an error naming the legal choices.
## Public API
@@ -944,4 +1074,4 @@ npm test
| `src/index.ts` | Package re-exports |
| `src/generated/` | Langium-generated files (git-ignored, rebuilt by `npm run build`) |
| `textmate-postprocess.mjs` | Runs after `langium generate`: gives a hyphenated name its color back and adds a scope for numbers and operators |
-| `syntaxes/` | TextMate grammar (git-ignored, generated by `langium generate` and adjusted by `textmate-postprocess.mjs`) |
+| `syntaxes/` | TextMate grammar (git-ignored, generated by `langium generate` and adjusted by `textmate-postprocess.mjs`); `packages/extension` layers an injection grammar over it for code inside a fenced script |
diff --git a/packages/language/package.json b/packages/language/package.json
index 82fc36f..04bfb12 100644
--- a/packages/language/package.json
+++ b/packages/language/package.json
@@ -1,7 +1,7 @@
{
"name": "@bpmn-script/language",
"description": "Langium grammar, validator and language server for BPMNscript",
- "version": "0.0.1",
+ "version": "0.1.0",
"license": "Apache-2.0",
"repository": {
"type": "git",
@@ -33,7 +33,8 @@
}
},
"scripts": {
- "clean": "shx rm -fr *.tsbuildinfo out",
+ "prepack": "node -e \"fs.cpSync('../../LICENSE', 'LICENSE')\"",
+ "clean": "node -e \"for (const f of [...fs.globSync('*.tsbuildinfo'), 'out']) fs.rmSync(f, { recursive: true, force: true })\"",
"build": "npm run langium:generate && tsc -p tsconfig.src.json",
"build:clean": "npm run clean && npm run build",
"langium:generate": "langium generate && node textmate-postprocess.mjs",
@@ -42,11 +43,11 @@
"test": "vitest run"
},
"dependencies": {
- "langium": "^4.3.1",
+ "langium": "^4.4.0",
"vscode-languageserver-types": "^3.18.3"
},
"devDependencies": {
- "langium-cli": "^4.3.0",
- "vitest": "^4.1.11"
+ "langium-cli": "^4.4.0",
+ "vitest": "^5.0.5"
}
}
diff --git a/packages/language/src/bpmn-script-completion.ts b/packages/language/src/bpmn-script-completion.ts
index 6660ea5..a4dcae1 100644
--- a/packages/language/src/bpmn-script-completion.ts
+++ b/packages/language/src/bpmn-script-completion.ts
@@ -1,6 +1,7 @@
import {
AstUtils,
GrammarAST,
+ GrammarUtils,
isCompositeCstNode,
isLeafCstNode,
type AstNode,
@@ -14,6 +15,7 @@ import {
DefaultCompletionProvider,
type CompletionAcceptor,
type CompletionContext,
+ type CompletionValueItem,
type NextFeature,
} from 'langium/lsp';
import {
@@ -53,6 +55,7 @@ import {
} from './bpmn-script-validator.js';
import {
isStructuralParenKey,
+ payloadDocumentationKeyOf,
payloadItemOf,
settingsOf,
timerParticleOf,
@@ -70,6 +73,7 @@ import {
CATCH_TRIGGERS,
DECLARED_CODE_TRIGGERS,
DECISION_RESULT_MAPPINGS,
+ ELSE_FAIL_WORD,
EMIT_TRIGGERS,
END_TRIGGERS,
ENGINE_KEYS,
@@ -96,6 +100,7 @@ import {
ON_TRIGGERS,
OUTPUT_DIRECTION,
parameterDirectionsFor,
+ printName,
PROCESS_HEADER_KEYS,
PROPERTY_DIRECTION,
RACE_TRIGGERS,
@@ -109,6 +114,7 @@ import {
TRIGGER_PAYLOAD,
TYPE_BINDING_KEY,
TYPE_BINDING_VALUES,
+ VALUE_DOCUMENTATION_KEYS,
VAR_TYPES,
type EngineKey,
} from './vocabulary.js';
@@ -130,6 +136,24 @@ const subscriptionChoices = (triggers: readonly string[]): string =>
.filter((word) => namesACode(word) && !DECLARED_CODE_TRIGGERS.has(word))
.join(',');
+/** A code is written bare, a subscription name quoted. */
+const triggerForms = (
+ word: string,
+ triggers: readonly string[],
+ body = '',
+): StructureForm[] => [
+ {
+ label: word,
+ insertText:
+ word + ' ${1|' + declaredCodeChoices(triggers) + '|}(${2:CODE})' + body,
+ },
+ {
+ label: `${word} message`,
+ insertText:
+ word + ' ${1|' + subscriptionChoices(triggers) + '|}("${2:NAME}")' + body,
+ },
+];
+
/** A keyword absent here keeps Langium's bare-keyword item. */
const STRUCTURE_SNIPPETS: Readonly<
Record
@@ -161,48 +185,10 @@ const STRUCTURE_SNIPPETS: Readonly<
],
subprocess: 'subprocess ${1:id} {\n\t$0\n}',
attempt: 'attempt ${1:id} {\n\t$0\n}',
- // A code is written bare, a subscription name quoted; timer and condition are
- // scaffolded at the trigger word.
- on: [
- {
- label: 'on',
- insertText:
- 'on ${1|' +
- declaredCodeChoices(ON_TRIGGERS) +
- '|}(${2:CODE}) {\n\t$0\n}',
- },
- {
- label: 'on message',
- insertText:
- 'on ${1|' +
- subscriptionChoices(ON_TRIGGERS) +
- '|}("${2:NAME}") {\n\t$0\n}',
- },
- ],
- throw: [
- {
- label: 'throw',
- insertText:
- 'throw ${1|' + declaredCodeChoices(THROW_TRIGGERS) + '|}(${2:CODE})',
- },
- {
- label: 'throw message',
- insertText:
- 'throw ${1|' + subscriptionChoices(THROW_TRIGGERS) + '|}("${2:NAME}")',
- },
- ],
- emit: [
- {
- label: 'emit',
- insertText:
- 'emit ${1|' + declaredCodeChoices(EMIT_TRIGGERS) + '|}(${2:CODE})',
- },
- {
- label: 'emit message',
- insertText:
- 'emit ${1|' + subscriptionChoices(EMIT_TRIGGERS) + '|}("${2:NAME}")',
- },
- ],
+ // Timer and condition are scaffolded at the trigger word.
+ on: triggerForms('on', ON_TRIGGERS, ' {\n\t$0\n}'),
+ throw: triggerForms('throw', THROW_TRIGGERS),
+ emit: triggerForms('emit', EMIT_TRIGGERS),
await: [
{
label: 'await',
@@ -252,6 +238,12 @@ const engineSnippets = (
const SETTING_SNIPPETS: Readonly> = {
label: 'label: "${1:label}"',
documentation: 'documentation: "${1:documentation}"',
+ ...Object.fromEntries(
+ Object.values(VALUE_DOCUMENTATION_KEYS).map((key) => [
+ key,
+ `${key}: "\${1:documentation}"`,
+ ]),
+ ),
...engineSnippets((key) => key),
...engineSnippets(joinSettingKey),
...engineSnippets(
@@ -387,15 +379,60 @@ const payloadOpen = (owner: AstNode, context: CompletionContext): boolean =>
function conditionSlotOpen(context: CompletionContext): boolean {
const owner = owningElement(context);
- const trigger = owner === undefined ? undefined : triggerWordOf(owner);
+ if (owner === undefined) return false;
+ const trigger = triggerWordOf(owner);
return (
- owner !== undefined &&
trigger !== undefined &&
TRIGGER_PAYLOAD[trigger]?.parens === 'condition' &&
!payloadWritten(owner, context)
);
}
+/**
+ * The items written inside the parentheses that hold a condition when the
+ * caret is there, where the validator accepts the condition's documentation
+ * alone.
+ */
+function conditionItemsAt(context: CompletionContext): ParenItem[] | undefined {
+ for (
+ let node: AstNode | undefined = context.node;
+ node;
+ node = node.$container
+ ) {
+ const owner = node as {
+ condition?: AstNode;
+ conditionItems?: ParenItem[];
+ completion?: AstNode;
+ completionItems?: ParenItem[];
+ };
+ for (const [value, items] of [
+ [owner.condition, owner.conditionItems],
+ [owner.completion, owner.completionItems],
+ ] as const) {
+ const start = value?.$cstNode?.end;
+ if (items === undefined || start === undefined) continue;
+ const close = GrammarUtils.findNodesForKeyword(node.$cstNode, ')').find(
+ (paren) => paren.offset >= start,
+ );
+ if (
+ close !== undefined &&
+ context.offset > start &&
+ context.offset <= close.offset
+ ) {
+ return items;
+ }
+ }
+ }
+ return undefined;
+}
+
+function conditionItemForms(items: ParenItem[]): StructureForm[] {
+ const key = VALUE_DOCUMENTATION_KEYS.condition;
+ return settingsOf(items).some((setting) => setting.key === key)
+ ? []
+ : settingForms([key]);
+}
+
/** The only flag any rule lists is the handler's `alongside`. */
function flagWordsFor(node: AstNode): readonly string[] {
const trigger = triggerWordOf(node);
@@ -410,7 +447,10 @@ function settingFormsFor(node: AstNode): StructureForm[] | undefined {
return settingForms(PROCESS_HEADER_KEYS);
}
if (isListener(node)) {
- return settingForms(LISTENER_BINDING_KEYS);
+ return settingForms([
+ ...LISTENER_BINDING_KEYS,
+ ...(node.event === 'timeout' ? [VALUE_DOCUMENTATION_KEYS.timer] : []),
+ ]);
}
if (isFormField(node)) {
return settingForms(FORM_FIELD_SETTING_KEYS);
@@ -442,10 +482,26 @@ function settingFormsFor(node: AstNode): StructureForm[] | undefined {
...own,
...ENGINE_KEYS,
...(rule.repeats && isRepeated(node) ? RUN_ENGINE_KEYS : []),
+ ...valueDocumentationKeysOf(node),
]),
];
}
+/** Offered only beside the value each documents. */
+function valueDocumentationKeysOf(node: AstNode): string[] {
+ const trigger = triggerWordOf(node);
+ const payloadKey =
+ trigger === undefined ? undefined : payloadDocumentationKeyOf(trigger);
+ const clause = node as { cardinality?: unknown; element?: string };
+ return [
+ ...(payloadKey === undefined ? [] : [payloadKey]),
+ ...(clause.cardinality === undefined
+ ? []
+ : [VALUE_DOCUMENTATION_KEYS.count]),
+ ...(clause.element === undefined ? [] : [VALUE_DOCUMENTATION_KEYS.each]),
+ ];
+}
+
const writtenKeysOf = (owner: AstNode): ReadonlySet =>
new Set(settingsOf(itemsOf(owner)).map((setting) => setting.key));
@@ -697,9 +753,23 @@ const STRUCTURE_DETAILS: Readonly> = {
for: 'how often the preceding step runs',
};
-const FLAG_DETAIL = 'BPMNscript flag';
-const FORM_TYPE_DETAIL = 'BPMNscript form type';
-const SETTING_VALUE_DETAIL = 'BPMNscript setting value';
+const DIRECTION_DETAILS: Readonly> = {
+ [INPUT_DIRECTION]: 'a value handed to this step',
+ [OUTPUT_DIRECTION]: 'a value this step hands back',
+ [FIELD_DIRECTION]:
+ 'a value injected into the class, delegate, or built-in behaviour this step names',
+ [PROPERTY_DIRECTION]:
+ 'a value Tasklist or a worker reads off the step, never a variable',
+};
+
+/**
+ * A field lowers to `stringValue` or an expression and a property to `value`,
+ * so both are quoted.
+ */
+const DIRECTION_VALUES: Readonly> = {
+ [FIELD_DIRECTION]: '"${2:value}"',
+ [PROPERTY_DIRECTION]: '"${2:value}"',
+};
export class BpmnScriptCompletionProvider extends DefaultCompletionProvider {
private readonly variables: VariableSymbolProvider;
@@ -714,9 +784,6 @@ export class BpmnScriptCompletionProvider extends DefaultCompletionProvider {
next: NextFeature,
acceptor: CompletionAcceptor,
): MaybePromise {
- // While a keyword still opens several shapes the caret's node is the shared
- // rule, so the next feature decides.
- const nodeType = next.type ?? context.node?.$type;
const owner = owningElement(context);
if (
next.property === 'key' &&
@@ -725,9 +792,13 @@ export class BpmnScriptCompletionProvider extends DefaultCompletionProvider {
) {
// Until a required payload is written only it is offered; a timer's date
// and cycle keys are that payload.
- const forms = payloadOpen(owner, context)
- ? timerKeyForms(owner)
- : (settingFormsFor(owner) ?? []);
+ const conditionItems = conditionItemsAt(context);
+ const forms =
+ conditionItems !== undefined
+ ? conditionItemForms(conditionItems)
+ : payloadOpen(owner, context)
+ ? timerKeyForms(owner)
+ : (settingFormsFor(owner) ?? []);
for (const form of forms) {
this.acceptSnippet(context, acceptor, {
...form,
@@ -742,7 +813,12 @@ export class BpmnScriptCompletionProvider extends DefaultCompletionProvider {
AstUtils.getContainerOfType(context.node, isFormField)
) {
if (!GrammarAST.isKeyword(next.feature)) {
- this.acceptWords(context, acceptor, FORM_FIELD_TYPES, FORM_TYPE_DETAIL);
+ this.acceptWords(
+ context,
+ acceptor,
+ FORM_FIELD_TYPES,
+ 'BPMNscript form type',
+ );
}
return;
}
@@ -755,7 +831,12 @@ export class BpmnScriptCompletionProvider extends DefaultCompletionProvider {
const choices =
key === undefined ? undefined : SETTING_VALUE_CHOICES[key];
if (choices) {
- this.acceptWords(context, acceptor, choices, SETTING_VALUE_DETAIL);
+ this.acceptWords(
+ context,
+ acceptor,
+ choices,
+ 'BPMNscript setting value',
+ );
return;
}
}
@@ -777,6 +858,15 @@ export class BpmnScriptCompletionProvider extends DefaultCompletionProvider {
this.acceptListenerEvents(context, acceptor, owner);
return;
}
+ if (next.property === 'fail') {
+ this.acceptWords(
+ context,
+ acceptor,
+ [ELSE_FAIL_WORD],
+ 'stop the run with an error when no condition holds',
+ );
+ return;
+ }
if (next.property === 'kind' && next.type === CodeDecl.$type) {
for (const form of CODE_DECLARATION_FORMS) {
this.acceptSnippet(context, acceptor, form);
@@ -793,6 +883,9 @@ export class BpmnScriptCompletionProvider extends DefaultCompletionProvider {
}
return;
}
+ // While a keyword still opens several shapes the caret's node is the shared
+ // rule, so the next feature decides.
+ const nodeType = next.type ?? context.node?.$type;
if (next.property === 'trigger' && nodeType) {
const triggers = STATEMENT_TRIGGERS[nodeType];
if (triggers) {
@@ -836,6 +929,18 @@ export class BpmnScriptCompletionProvider extends DefaultCompletionProvider {
);
}
+ /** A name the plain form cannot spell is offered as written, in backticks. */
+ protected override createReferenceCompletionItem(
+ nodeDescription: AstNodeDescription,
+ refInfo: ReferenceInfo,
+ context: CompletionContext,
+ ): CompletionValueItem {
+ return {
+ ...super.createReferenceCompletionItem(nodeDescription, refInfo, context),
+ label: printName(nodeDescription.name),
+ };
+ }
+
protected override completionForCrossReference(
context: CompletionContext,
next: NextFeature,
@@ -986,37 +1091,16 @@ export class BpmnScriptCompletionProvider extends DefaultCompletionProvider {
}
}
- private static readonly DIRECTION_DETAILS: Readonly> =
- {
- [INPUT_DIRECTION]: 'a value handed to this step',
- [OUTPUT_DIRECTION]: 'a value this step hands back',
- [FIELD_DIRECTION]:
- 'a value injected into the class, delegate, or built-in behaviour this step names',
- [PROPERTY_DIRECTION]:
- 'a value Tasklist or a worker reads off the step, never a variable',
- };
-
- /**
- * A field lowers to `stringValue` or an expression and a property to `value`,
- * so both are quoted.
- */
- private static readonly DIRECTION_VALUES: Readonly> = {
- [FIELD_DIRECTION]: '"${2:value}"',
- [PROPERTY_DIRECTION]: '"${2:value}"',
- };
-
private acceptParameterDirections(
context: CompletionContext,
acceptor: CompletionAcceptor,
directions: readonly string[],
): void {
for (const direction of directions) {
- const value =
- BpmnScriptCompletionProvider.DIRECTION_VALUES[direction] ??
- '${2:value}';
+ const value = DIRECTION_VALUES[direction] ?? '${2:value}';
this.acceptSnippet(context, acceptor, {
label: direction,
- detail: BpmnScriptCompletionProvider.DIRECTION_DETAILS[direction],
+ detail: DIRECTION_DETAILS[direction],
insertText: `${direction} \${1:name} = ${value}`,
});
}
@@ -1077,7 +1161,7 @@ export class BpmnScriptCompletionProvider extends DefaultCompletionProvider {
!payloadOpen(owner, context) &&
flagWordsFor(owner).includes(keyword.value)
) {
- this.acceptWords(context, acceptor, [keyword.value], FLAG_DETAIL);
+ this.acceptWords(context, acceptor, [keyword.value], 'BPMNscript flag');
}
return;
}
diff --git a/packages/language/src/bpmn-script-hover.ts b/packages/language/src/bpmn-script-hover.ts
index c90cf43..9696de1 100644
--- a/packages/language/src/bpmn-script-hover.ts
+++ b/packages/language/src/bpmn-script-hover.ts
@@ -21,7 +21,7 @@ import {
EVENT_MESSAGE_FIELD,
} from './vocabulary.js';
import { isVariableSymbolNode } from './bpmn-script-references.js';
-import { declaredCodeOf, settingsOf } from './paren-items.js';
+import { settingsOf } from './paren-items.js';
function literalSetting(items: ParenItem[], key: string): string | undefined {
const setting = settingsOf(items).find((item) => item.key === key);
@@ -40,12 +40,9 @@ function namedStatementHover(node: NamedStatement): string {
function codeDeclHover(decl: CodeDecl): string {
const article = /^[aeiou]/i.test(decl.kind) ? 'an' : 'a';
let line = `${article} ${decl.kind} '${decl.name}'`;
- // `declaredCodeOf` falls back to the name; hover quotes only a written setting.
- const hasCodeSetting = settingsOf(decl.items).some(
- (item) => item.key === EVENT_CODE_FIELD,
- );
- const code = hasCodeSetting ? declaredCodeOf(decl) : undefined;
- if (code !== undefined) line += ` with code "${code}"`;
+ // Not `declaredCodeOf`, which falls back to the name; an empty code is not quoted.
+ const code = literalSetting(decl.items, EVENT_CODE_FIELD);
+ if (code) line += ` with code "${code}"`;
const message = literalSetting(decl.items, EVENT_MESSAGE_FIELD);
if (message !== undefined) line += `: ${message}`;
return line;
diff --git a/packages/language/src/bpmn-script-linker.ts b/packages/language/src/bpmn-script-linker.ts
index 6e20fc4..19a1520 100644
--- a/packages/language/src/bpmn-script-linker.ts
+++ b/packages/language/src/bpmn-script-linker.ts
@@ -27,6 +27,7 @@ import {
type NamedStatement,
} from './bpmn-script-scope-provider.js';
import { codeTriggerOf, payloadTextOf } from './paren-items.js';
+import { diagnosticText, printName } from './vocabulary.js';
/** First match wins: duplicate names are a validator error. */
function findNamedStatement(
@@ -106,28 +107,30 @@ export class BpmnScriptLinker extends DefaultLinker {
targetDescription?: AstNodeDescription,
): LinkingError {
const source = refInfo.container;
+ const name = refInfo.reference.$refText;
const codeTrigger = codeTriggerOf(source);
if (codeTrigger !== undefined) {
- const name = refInfo.reference.$refText;
// Advising a second declaration under the other kind would lead to the duplicate-name error.
const declaredKind = declaredCodeKind(source, name);
const message =
declaredKind === undefined
- ? `'${name}' is not declared. Add '${codeTrigger} ${name}' to the process.`
- : `'${name}' is declared as an ${declaredKind}, not an ${codeTrigger}.`;
+ ? diagnosticText(
+ `'${name}' is not declared`,
+ `help: add '${codeTrigger} ${printName(name)}' to the process`,
+ )
+ : `'${name}' is declared as an ${declaredKind}, not an ${codeTrigger}`;
return { info: refInfo, message };
}
const isHost = isOnHandler(source) && refInfo.property === 'host';
const isGotoTarget =
isGotoStatement(source) && refInfo.property === 'target';
if (isHost || isGotoTarget) {
- const name = refInfo.reference.$refText;
const process = AstUtils.getContainerOfType(source, isProcess);
const target = process ? findNamedStatement(process, name) : undefined;
if (process && !target) {
const message = isHost
- ? `No step named '${name}' in this process to attach to.`
- : `No step named '${name}' in this process.`;
+ ? `no step named '${name}' in this process to attach to`
+ : `no step named '${name}' in this process`;
return { info: refInfo, message };
}
const sourceContainer = enclosingFlowContainer(source);
@@ -138,16 +141,23 @@ export class BpmnScriptLinker extends DefaultLinker {
if (located) {
const { phrase, crossesHandler } = located;
const boundary = isHost
- ? `a boundary event attaches to an activity in its own scope.`
+ ? ['note: a boundary event attaches to an activity in its own scope']
: crossesHandler
- ? `a goto cannot cross an event handler boundary: an event handler's steps run only when its event fires.`
- : `a goto cannot cross a subprocess boundary.`;
+ ? [
+ 'note: a goto cannot cross an event handler boundary',
+ "note: an event handler's steps run only when its event fires",
+ ]
+ : ['note: a goto cannot cross a subprocess boundary'];
return {
info: refInfo,
- message: `'${refInfo.reference.$refText}' is ${phrase}; ${boundary}`,
+ message: diagnosticText(`'${name}' is ${phrase}`, ...boundary),
};
}
}
- return super.createLinkingError(refInfo, targetDescription);
+ // Langium's own wording names the grammar type the reference expects.
+ return {
+ ...super.createLinkingError(refInfo, targetDescription),
+ message: `nothing named '${name}' is in reach here`,
+ };
}
}
diff --git a/packages/language/src/bpmn-script-module.ts b/packages/language/src/bpmn-script-module.ts
index 2efa864..06dc6bc 100644
--- a/packages/language/src/bpmn-script-module.ts
+++ b/packages/language/src/bpmn-script-module.ts
@@ -1,4 +1,4 @@
-import { type Module, inject } from 'langium';
+import { type Module, createGrammarConfig, inject } from 'langium';
import {
createDefaultModule,
createDefaultSharedModule,
@@ -24,11 +24,17 @@ import { BpmnScriptCompletionProvider } from './bpmn-script-completion.js';
import { BpmnScriptDocumentValidator } from './bpmn-script-document-validator.js';
import { BpmnScriptScopeProvider } from './bpmn-script-scope-provider.js';
import { BpmnScriptLinker } from './bpmn-script-linker.js';
-import { BpmnScriptParserErrorMessageProvider } from './bpmn-script-parser-error-message-provider.js';
+import {
+ BpmnScriptLexerErrorMessageProvider,
+ BpmnScriptParserErrorMessageProvider,
+} from './bpmn-script-parser-error-message-provider.js';
import { BpmnScriptSemanticTokenProvider } from './bpmn-script-semantic-tokens.js';
import { BpmnScriptValueConverter } from './bpmn-script-value-converter.js';
import { BpmnScriptHoverProvider } from './bpmn-script-hover.js';
-import { BpmnScriptReferences } from './bpmn-script-references.js';
+import {
+ BpmnScriptReferences,
+ BpmnScriptRenameProvider,
+} from './bpmn-script-references.js';
import {
BpmnScriptDocumentSymbolProvider,
BpmnScriptNodeKindProvider,
@@ -52,7 +58,13 @@ export const BpmnScriptModule: Module<
parser: {
ParserErrorMessageProvider: (services) =>
new BpmnScriptParserErrorMessageProvider(services),
+ LexerErrorMessageProvider: () => new BpmnScriptLexerErrorMessageProvider(),
ValueConverter: () => new BpmnScriptValueConverter(),
+ // A caret on a name's opening backtick still names it.
+ GrammarConfig: (services) => ({
+ ...createGrammarConfig(services),
+ nameRegexp: /^[\w\p{L}`]$/u,
+ }),
},
references: {
VariableSymbolProvider: () => new DefaultVariableSymbolProvider(),
@@ -70,6 +82,7 @@ export const BpmnScriptModule: Module<
SemanticTokenProvider: (services) =>
new BpmnScriptSemanticTokenProvider(services),
HoverProvider: (services) => new BpmnScriptHoverProvider(services),
+ RenameProvider: (services) => new BpmnScriptRenameProvider(services),
DocumentSymbolProvider: (services) =>
new BpmnScriptDocumentSymbolProvider(services),
},
diff --git a/packages/language/src/bpmn-script-parser-error-message-provider.ts b/packages/language/src/bpmn-script-parser-error-message-provider.ts
index d9de744..7e509e5 100644
--- a/packages/language/src/bpmn-script-parser-error-message-provider.ts
+++ b/packages/language/src/bpmn-script-parser-error-message-provider.ts
@@ -1,51 +1,51 @@
/**
- * Guidance in place of Chevrotain's stock wording; recovery is unchanged. A
- * reserved word arrives as a token mismatch where the grammar expects `ID` and
- * as no viable alternative where `ID` is one choice, so both are overridden.
+ * Plain wording in place of Chevrotain's token-type lists; recovery is
+ * unchanged. A reserved word arrives as a token mismatch where the grammar
+ * expects `ID` and as no viable alternative where `ID` is one choice, so both
+ * are overridden.
*/
import {
+ DefaultLexerErrorMessageProvider,
LangiumParserErrorMessageProvider,
type LangiumCoreServices,
} from 'langium';
import {
DECLARED_CODE_TRIGGERS,
+ diagnosticText,
+ ELSE_FAIL_WORD,
+ formatPlainWordList,
formatWordList,
IO_DIRECTIONS,
reservedWordsOf,
} from './vocabulary.js';
const ID_TOKEN_NAME = 'ID';
-
-/**
- * A misplaced `var` or `for` ends the statement list early; at `EOF` the stock
- * message would say "found ``".
- */
-const CLOSE_BRACE_TOKEN_NAME = '}';
-const VAR_KEYWORD_TOKEN_NAME = 'var';
-const FOR_KEYWORD_TOKEN_NAME = 'for';
const EOF_TOKEN_NAME = 'EOF';
+const ELSE_KEYWORD = 'else';
-/**
- * A mistyped statement keyword parses as a code declaration and fails at the
- * name slot; a real declaration word is excluded.
- */
-const CODE_DECL_RULE_NAME = 'CodeDecl';
+const STEP_KEYWORD_NOTE =
+ 'note: every step starts with a keyword such as ' +
+ "'start', 'user', 'service', 'if', 'on', 'throw', or 'emit'";
-/**
- * After the first step a plain word ends the process body early. In a braced
- * block the same word opens a parameter (`direction=ID name=ID '='`) and fails
- * at its name slot or at its `=`, where only the name is left to quote.
- */
-const PROCESS_RULE_NAME = 'Process';
-const IO_PARAMETER_RULE_NAME = 'IoParameter';
-const EQUALS_TOKEN_NAME = '=';
-const CLOSE_PAREN_TOKEN_NAME = ')';
+/** What each terminal means to an author; a keyword token is named after its text. */
+const TERMINAL_NOUNS: Readonly> = {
+ ID: 'a name',
+ INT: 'a number',
+ DECIMAL: 'a number',
+ STRING: 'a quoted string',
+ RAW_TEMPLATE: 'a "${...}" expression',
+ QUOTED_NAME: 'a name',
+ FENCED_SCRIPT: 'a fenced script',
+ EOF: 'the end of the file',
+};
+
+/** These three starting the alternatives mean any value fits. */
+const VALUE_START_TOKENS = ['ID', 'INT', 'STRING'];
-const STEP_KEYWORD_HINT =
- 'every step starts with a keyword such as ' +
- "'start', 'user', 'service', 'if', 'on', 'throw', 'emit', ...";
+/** More choices than this read as noise, so the message names the found token instead. */
+const MAX_LISTED_CHOICES = 4;
const WORD_SHAPED = /^[A-Za-z_]/;
@@ -61,6 +61,59 @@ type MismatchTokenOptions = Parameters<
type NoViableAltOptions = Parameters<
LangiumParserErrorMessageProvider['buildNoViableAltMessage']
>[0];
+type EarlyExitOptions = Parameters<
+ LangiumParserErrorMessageProvider['buildEarlyExitMessage']
+>[0];
+type NotAllInputParsedOptions = Parameters<
+ LangiumParserErrorMessageProvider['buildNotAllInputParsedMessage']
+>[0];
+type Token = MismatchTokenOptions['actual'];
+type TokenType = MismatchTokenOptions['expected'];
+
+function tokenNoun(tokenName: string): string {
+ return TERMINAL_NOUNS[tokenName] ?? `'${tokenName.replace(/:KW$/, '')}'`;
+}
+
+/** A token spanning lines, such as a fenced script, is named by its kind so the headline stays one line. */
+function tokenPhrase(token: Token): string {
+ return token.image.includes('\n')
+ ? tokenNoun(token.tokenType.name)
+ : `'${token.image}'`;
+}
+
+function foundPhrase(token: Token | undefined): string {
+ return token === undefined || token.tokenType.name === EOF_TOKEN_NAME
+ ? 'the end of the file'
+ : tokenPhrase(token);
+}
+
+/** Chevrotain hands a placeholder with an empty image when nothing came before. */
+function afterPhrase(previous: Token | undefined): string {
+ return previous?.image ? ` after ${tokenPhrase(previous)}` : '';
+}
+
+/** The first token of every path, described once each. */
+function choiceNouns(paths: readonly (readonly TokenType[])[]): string[] {
+ const names = [
+ ...new Set(paths.flatMap((path) => (path[0] ? [path[0].name] : []))),
+ ];
+ if (VALUE_START_TOKENS.every((name) => names.includes(name))) {
+ return ['a value'];
+ }
+ return [...new Set(names.map(tokenNoun))];
+}
+
+function expectedOrUnexpected(
+ paths: readonly (readonly TokenType[])[],
+ actual: Token | undefined,
+ previous: Token | undefined,
+): string {
+ const nouns = choiceNouns(paths);
+ if (nouns.length > 0 && nouns.length <= MAX_LISTED_CHOICES) {
+ return `expected ${formatPlainWordList(nouns)}${afterPhrase(previous)}`;
+ }
+ return `unexpected ${foundPhrase(actual)}${afterPhrase(previous)}`;
+}
export class BpmnScriptParserErrorMessageProvider extends LangiumParserErrorMessageProvider {
private readonly services: LangiumCoreServices;
@@ -73,107 +126,114 @@ export class BpmnScriptParserErrorMessageProvider extends LangiumParserErrorMess
override buildMismatchTokenMessage(options: MismatchTokenOptions): string {
const { expected, actual } = options;
const rule = bareRuleName(options.ruleName);
- if (expected.name === CLOSE_PAREN_TOKEN_NAME) {
- const where =
- actual.tokenType.name === EOF_TOKEN_NAME
- ? 'the end of the file'
- : `'${actual.image}'`;
- return `Expected ')' before ${where}: a '(' is still open.`;
+ if (expected.name === ')') {
+ return diagnosticText(
+ `expected ')' before ${foundPhrase(actual)}`,
+ "note: a '(' is still open",
+ );
}
- if (
- expected.name === EQUALS_TOKEN_NAME &&
- rule === IO_PARAMETER_RULE_NAME
- ) {
- return (
- `Expected '=' after '${options.previous.image}': inside a block, two ` +
- "plain words start a parameter such as 'input name = value'; " +
- STEP_KEYWORD_HINT
+ // In a braced block a plain word opens a parameter
+ // (`direction=ID name=ID '='`) and fails at its name slot or at its `=`,
+ // where only the name is left to quote.
+ if (expected.name === '=' && rule === 'IoParameter') {
+ return diagnosticText(
+ `expected '=' after '${options.previous.image}'`,
+ "note: inside a block, two plain words start a parameter such as 'input name = value'",
+ STEP_KEYWORD_NOTE,
);
}
- if (expected.name === CLOSE_BRACE_TOKEN_NAME) {
- if (actual.tokenType.name === VAR_KEYWORD_TOKEN_NAME) {
- return this.varPlacementMessage();
- }
- if (actual.tokenType.name === FOR_KEYWORD_TOKEN_NAME) {
- return this.repeatClausePlacementMessage();
- }
- if (actual.tokenType.name === EOF_TOKEN_NAME) {
- return this.unclosedBlockMessage();
- }
- if (
- actual.tokenType.name === ID_TOKEN_NAME &&
- rule === PROCESS_RULE_NAME
- ) {
- return `'${actual.image}' is not a step keyword; ${STEP_KEYWORD_HINT}`;
+ // A misplaced `var` or `for`, or a plain word after the first step, ends the
+ // statement list early; at `EOF` the stock message would say "found ``".
+ if (expected.name === '}') {
+ const found = actual.tokenType.name;
+ if (found === 'var') return VAR_PLACEMENT_MESSAGE;
+ if (found === 'for') return REPEAT_CLAUSE_PLACEMENT_MESSAGE;
+ if (found === EOF_TOKEN_NAME) return UNCLOSED_BLOCK_MESSAGE;
+ if (found === ID_TOKEN_NAME && rule === 'Process') {
+ return stepKeywordMessage(actual.image);
}
}
if (expected.name === ID_TOKEN_NAME) {
+ if (options.previous.image === ELSE_KEYWORD) return ELSE_FOLLOWER_MESSAGE;
if (this.isReservedWord(actual.tokenType.name)) {
- return this.reservedWordMessage(actual.image);
+ return reservedWordMessage(actual.image);
}
const word = options.previous.image;
- if (rule === CODE_DECL_RULE_NAME && !DECLARED_CODE_TRIGGERS.has(word)) {
- return this.declarationOrStepMessage(word);
+ // A mistyped statement keyword parses as a code declaration and fails at
+ // the name slot.
+ if (rule === 'CodeDecl' && !DECLARED_CODE_TRIGGERS.has(word)) {
+ return declarationOrStepMessage(word);
}
- if (rule === IO_PARAMETER_RULE_NAME && !IO_DIRECTIONS.includes(word)) {
- return `'${word}' is not a step keyword; ${STEP_KEYWORD_HINT}`;
+ if (rule === 'IoParameter' && !IO_DIRECTIONS.includes(word)) {
+ return stepKeywordMessage(word);
}
}
- return super.buildMismatchTokenMessage(options);
- }
-
- private varPlacementMessage(): string {
- return (
- "A variable declaration ('var ...') must come before the first step in " +
- 'the process, with the other declarations. Move it above the first ' +
- 'statement.'
- );
- }
-
- private repeatClausePlacementMessage(): string {
- return (
- "A repeat clause ('for ...') attaches to the step that repeats. " +
- 'The statement before it does not take one; move the clause onto ' +
- 'the step that should.'
- );
- }
-
- private unclosedBlockMessage(): string {
- return "Expected '}' before the end of the file: a block is still open.";
- }
-
- private declarationOrStepMessage(word: string): string {
- return (
- `'${word}' is neither a known declaration nor a step keyword. ` +
- 'A declaration starting with a plain word is ' +
- `${formatWordList([...DECLARED_CODE_TRIGGERS])} followed by the name it ` +
- `declares; ${STEP_KEYWORD_HINT}`
- );
+ if (expected.name === EOF_TOKEN_NAME) {
+ return outsideProcessMessage(actual);
+ }
+ return `expected ${tokenNoun(expected.name)}${afterPhrase(options.previous)}`;
}
override buildNoViableAltMessage(options: NoViableAltOptions): string {
const actual = options.actual[0];
+ if (options.previous.image === ELSE_KEYWORD) return ELSE_FOLLOWER_MESSAGE;
+ const rule = bareRuleName(options.ruleName);
+ // A `Name` is a choice of two tokens, so a bad one arrives as no viable
+ // alternative inside it rather than as a mismatch in the rule holding it.
+ // The only `Name` after a plain word is a code declaration's.
+ const inName = rule === 'Name';
if (
actual &&
this.isReservedWord(actual.tokenType.name) &&
this.expectsIdentifier(options.expectedPathsPerAlt)
) {
- return this.reservedWordMessage(actual.image);
+ return inName
+ ? reservedNameMessage(actual.image)
+ : reservedWordMessage(actual.image);
+ }
+ const word = options.previous.image;
+ if (
+ rule === 'IoParameter' &&
+ options.previous.tokenType.name === ID_TOKEN_NAME &&
+ !IO_DIRECTIONS.includes(word)
+ ) {
+ return stepKeywordMessage(word);
+ }
+ if (
+ inName &&
+ options.previous.tokenType.name === ID_TOKEN_NAME &&
+ !DECLARED_CODE_TRIGGERS.has(word)
+ ) {
+ return declarationOrStepMessage(word);
}
if (actual && WORD_SHAPED.test(actual.image)) {
const words = this.keywordAlternatives(options.expectedPathsPerAlt);
if (words) {
- return this.wordAlternativeMessage(actual.image, words);
+ return diagnosticText(
+ `'${actual.image}' is not a word this position takes`,
+ `help: write ${formatWordList(words)}`,
+ );
}
}
- return super.buildNoViableAltMessage(options);
+ return expectedOrUnexpected(
+ options.expectedPathsPerAlt.flat(),
+ actual,
+ options.previous,
+ );
}
- private wordAlternativeMessage(
- word: string,
- alternatives: readonly string[],
+ override buildEarlyExitMessage(options: EarlyExitOptions): string {
+ return expectedOrUnexpected(
+ options.expectedIterationPaths,
+ options.actual[0],
+ options.previous,
+ );
+ }
+
+ override buildNotAllInputParsedMessage(
+ options: NotAllInputParsedOptions,
): string {
- return `'${word}' is not a word this position takes; write ${formatWordList(alternatives)}.`;
+ return outsideProcessMessage(options.firstRedundant);
}
/** `undefined` unless every alternative is a single keyword. */
@@ -192,14 +252,6 @@ export class BpmnScriptParserErrorMessageProvider extends LangiumParserErrorMess
return words.length > 0 ? words : undefined;
}
- private reservedWordMessage(word: string): string {
- const rawFallback = '"${' + word + '}"';
- return (
- `'${word}' is a reserved word and cannot be used as a plain name here. ` +
- `To refer to a variable named '${word}', write it as a quoted raw expression: ${rawFallback}.`
- );
- }
-
private isReservedWord(tokenName: string): boolean {
return reservedWordsOf(this.services.Grammar).has(tokenName);
}
@@ -212,3 +264,65 @@ export class BpmnScriptParserErrorMessageProvider extends LangiumParserErrorMess
);
}
}
+
+const VAR_PLACEMENT_MESSAGE = diagnosticText(
+ "a variable declaration ('var ...') comes after the first step",
+ 'note: declarations come before the first step of the process',
+ 'help: move it above the first statement',
+);
+
+const REPEAT_CLAUSE_PLACEMENT_MESSAGE = diagnosticText(
+ "a repeat clause ('for ...') follows a statement that does not take one",
+ 'note: a repeat clause attaches to the step that repeats',
+ 'help: move the clause onto the step that should repeat',
+);
+
+// Only `fail` follows `else` as a word, so a keyword there is no misspelt name.
+const ELSE_FOLLOWER_MESSAGE = `expected '{' or '${ELSE_FAIL_WORD}' after '${ELSE_KEYWORD}'`;
+
+const UNCLOSED_BLOCK_MESSAGE = diagnosticText(
+ "expected '}' before the end of the file",
+ 'note: a block is still open',
+);
+
+function outsideProcessMessage(token: Token): string {
+ return `unexpected ${foundPhrase(token)} outside any process`;
+}
+
+function stepKeywordMessage(word: string): string {
+ return diagnosticText(`'${word}' is not a step keyword`, STEP_KEYWORD_NOTE);
+}
+
+function declarationOrStepMessage(word: string): string {
+ return diagnosticText(
+ `'${word}' is neither a known declaration nor a step keyword`,
+ `note: a declaration starting with a plain word is ${formatWordList([...DECLARED_CODE_TRIGGERS])} followed by the name it declares`,
+ STEP_KEYWORD_NOTE,
+ );
+}
+
+function reservedNameMessage(word: string): string {
+ return diagnosticText(
+ `'${word}' is a reserved word and cannot be a plain name here`,
+ `help: to use '${word}' as the name, write it in backticks as '\`${word}\`'`,
+ );
+}
+
+function reservedWordMessage(word: string): string {
+ return diagnosticText(
+ `'${word}' is a reserved word and cannot be a plain name here`,
+ `help: to refer to a variable named '${word}', write the quoted raw expression "\${${word}}"`,
+ );
+}
+
+/** Chevrotain's own wording quotes the character between arrows and adds offsets. */
+export class BpmnScriptLexerErrorMessageProvider extends DefaultLexerErrorMessageProvider {
+ override buildUnexpectedCharactersMessage(
+ fullText: string,
+ startOffset: number,
+ length: number,
+ ): string {
+ const text = fullText.substring(startOffset, startOffset + length);
+ return `unexpected ${length === 1 ? 'character' : 'characters'} '${text}'`;
+ }
+}
diff --git a/packages/language/src/bpmn-script-references.ts b/packages/language/src/bpmn-script-references.ts
index 6be8925..36b3a6c 100644
--- a/packages/language/src/bpmn-script-references.ts
+++ b/packages/language/src/bpmn-script-references.ts
@@ -18,6 +18,7 @@ import {
type ReferenceDescription,
type Stream,
} from 'langium';
+import { DefaultRenameProvider } from 'langium/lsp';
import {
isProcess,
isVarRef,
@@ -26,6 +27,7 @@ import {
} from './generated/ast.js';
import type { BpmnScriptServices } from './bpmn-script-module.js';
import { isVariableUse } from './bpmn-script-validator.js';
+import { printName, unquoteName } from './vocabulary.js';
import type {
DeclaringSite,
VariableSymbolProvider,
@@ -143,3 +145,39 @@ export class BpmnScriptReferences extends DefaultReferences {
};
}
}
+
+type RenameArgs = Parameters;
+
+/**
+ * A step or code renamed to text the plain form cannot spell is written in
+ * backticks at every site; a variable has no backtick form.
+ */
+export class BpmnScriptRenameProvider extends DefaultRenameProvider {
+ override async rename(
+ ...[document, params, cancelToken]: RenameArgs
+ ): ReturnType {
+ const typed = /^`.+`$/.test(params.newName)
+ ? unquoteName(params.newName)
+ : params.newName;
+ const newName = this.renamesVariable(document, params)
+ ? typed
+ : printName(typed);
+ return super.rename(document, { ...params, newName }, cancelToken);
+ }
+
+ private renamesVariable(
+ document: LangiumDocument,
+ params: RenameArgs[1],
+ ): boolean {
+ const root = document.parseResult.value.$cstNode;
+ const leaf =
+ root &&
+ CstUtils.findDeclarationNodeAtOffset(
+ root,
+ document.textDocument.offsetAt(params.position),
+ this.grammarConfig.nameRegexp,
+ );
+ const [target] = leaf ? this.references.findDeclarations(leaf) : [];
+ return target !== undefined && isVariableSymbolNode(target);
+ }
+}
diff --git a/packages/language/src/bpmn-script-scope-provider.ts b/packages/language/src/bpmn-script-scope-provider.ts
index 7758510..74b5514 100644
--- a/packages/language/src/bpmn-script-scope-provider.ts
+++ b/packages/language/src/bpmn-script-scope-provider.ts
@@ -86,9 +86,10 @@ export function isNamedStatement(node: AstNode): node is NamedStatement {
isBusinessRuleTask(node) ||
isSubProcess(node) ||
isCallActivity(node) ||
- ((isThrowStatement(node) || isEmitStatement(node)) &&
- node.name !== undefined) ||
- (isIntermediateCatchEvent(node) && node.name !== undefined)
+ ((isThrowStatement(node) ||
+ isEmitStatement(node) ||
+ isIntermediateCatchEvent(node)) &&
+ node.name !== undefined)
);
}
diff --git a/packages/language/src/bpmn-script-semantic-tokens.ts b/packages/language/src/bpmn-script-semantic-tokens.ts
index d093f61..2f57c67 100644
--- a/packages/language/src/bpmn-script-semantic-tokens.ts
+++ b/packages/language/src/bpmn-script-semantic-tokens.ts
@@ -16,10 +16,12 @@ import {
isEndEvent,
isErrorMapping,
isFormField,
+ isIfStatement,
isIntermediateCatchEvent,
isIoParameter,
isListener,
isOnHandler,
+ isParallelStatement,
isRaceBranch,
isSetting,
isStartEvent,
@@ -59,6 +61,10 @@ export class BpmnScriptSemanticTokenProvider extends AbstractSemanticTokenProvid
if (node.particle) {
keyword('particle');
}
+ } else if (isIfStatement(node) || isParallelStatement(node)) {
+ if (node.fail !== undefined) {
+ keyword('fail');
+ }
} else if (isErrorMapping(node)) {
keyword('trigger');
keyword('when');
diff --git a/packages/language/src/bpmn-script-symbols.ts b/packages/language/src/bpmn-script-symbols.ts
index ac895cd..1cb85b7 100644
--- a/packages/language/src/bpmn-script-symbols.ts
+++ b/packages/language/src/bpmn-script-symbols.ts
@@ -25,7 +25,8 @@ const SYMBOL_KIND_BY_TYPE: Readonly> = {
export class BpmnScriptNodeKindProvider extends DefaultNodeKindProvider {
override getSymbolKind(node: AstNode | AstNodeDescription): SymbolKind {
- const type = 'type' in node ? node.type : node.$type;
+ // A VarDecl node has a `type` of its own (its declared type), so test `$type` first.
+ const type = '$type' in node ? node.$type : node.type;
return SYMBOL_KIND_BY_TYPE[type] ?? super.getSymbolKind(node);
}
}
diff --git a/packages/language/src/bpmn-script-validator.ts b/packages/language/src/bpmn-script-validator.ts
index 0f64c47..a678213 100644
--- a/packages/language/src/bpmn-script-validator.ts
+++ b/packages/language/src/bpmn-script-validator.ts
@@ -6,6 +6,7 @@
import {
AstUtils,
+ GrammarUtils,
type AstNode,
type ValidationAcceptor,
type ValidationChecks,
@@ -19,6 +20,7 @@ import type {
CallActivity,
CodeDecl,
DoWhileStatement,
+ ElseIf,
EmitStatement,
EndEvent,
Expr,
@@ -34,6 +36,7 @@ import type {
Model,
Multiplicative,
OnHandler,
+ ParallelBranch,
ParallelStatement,
ParenItem,
ParenValue,
@@ -136,7 +139,6 @@ import {
attributeBlockRuleOf,
BOOLEAN_SETTING_KEYS,
BUILTIN_FIELD_NAMES,
- BUILTIN_FIELD_VALIDATOR,
BUILTIN_REQUIRED_FIELDS,
BUSINESS_RULE_BINDING_KEYS,
CALL_BINDING_VALUES,
@@ -144,8 +146,10 @@ import {
CATCH_TRIGGERS,
DATE_PATTERN_KEY,
DECLARED_CODE_TRIGGERS,
+ DOCUMENTATION_KEY,
DECISION_MODIFIER_KEYS,
DECISION_RESULT_MAPPINGS,
+ diagnosticText,
EMIT_TRIGGERS,
END_TRIGGERS,
ENGINE_KEYS,
@@ -171,7 +175,10 @@ import {
formatPlainWordList,
formatWordList,
gatewayStatementRuleOf,
- ID_TEXT,
+ ELSE_FAIL_WORD,
+ ENGINE_ID_TEXT,
+ printName,
+ INPUT_DIRECTION,
IO_DIRECTIONS,
JOIN_ENGINE_KEYS,
JOIN_KEY_BY_ENGINE_KEY,
@@ -206,7 +213,10 @@ import {
TRIGGER_PAYLOAD,
TYPE_BINDING_KEY,
TYPE_BINDING_VALUES,
+ USER_TASK_DUE_DATE_KEYS,
+ USER_TASK_PRIORITY_KEY,
USER_TASK_VERBATIM_KEYS,
+ VALUE_DOCUMENTATION_KEYS,
type AttributeBlockRule,
type AttributeOwner,
type BuiltinTaskType,
@@ -235,9 +245,9 @@ export function registerValidationChecks(services: BpmnScriptServices) {
UserTask: validator.checkUserTask,
ServiceTask: validator.checkServiceTaskAttributes,
ScriptTask: validator.checkScriptTask,
- GenericTask: validator.checkAttributeOwner,
+ GenericTask: validator.checkAttributeBlock,
SendTask: validator.checkServiceTaskAttributes,
- ReceiveTask: validator.checkAttributeOwner,
+ ReceiveTask: validator.checkAttributeBlock,
BusinessRuleTask: validator.checkBusinessRuleTask,
IfStatement: validator.checkIfStatement,
WhileStatement: validator.checkWhileStatement,
@@ -252,7 +262,9 @@ export function registerValidationChecks(services: BpmnScriptServices) {
EmitStatement: validator.checkEmitStatement,
IntermediateCatchEvent: validator.checkIntermediateCatchEvent,
ParenValue: validator.checkParenValue,
+ ParenItem: validator.checkConditionItem,
Block: validator.checkBlock,
+ IoParameter: validator.checkIoParameterName,
};
registry.register(checks, validator);
}
@@ -269,8 +281,6 @@ type GatewayStatement =
| ParallelStatement
| RaceStatement;
-const USER_PRIORITY_KEY = 'priority';
-
/**
* A bareword under these names no variable: no undeclared warning, no JUEL
* scan. `assignee` lowers to a plain user id; the date keys are in so a
@@ -283,26 +293,26 @@ export const NON_VARIABLE_ATTR_KEYS: ReadonlySet = new Set([
...BUSINESS_RULE_BINDING_KEYS,
...DECISION_MODIFIER_KEYS,
'process',
- ...USER_TASK_VERBATIM_KEYS.filter((key) => key !== USER_PRIORITY_KEY),
+ ...USER_TASK_VERBATIM_KEYS.filter((key) => key !== USER_TASK_PRIORITY_KEY),
...engineSpellings('retryCycle'),
'resultVariable',
'initiator',
'validator',
...Object.values(CALL_MAPPER_KEY_BY_KIND),
+ ...Object.values(VALUE_DOCUMENTATION_KEYS),
]);
const TIMER_JOB_KEYS_WITHOUT_PRIORITY: readonly string[] =
TIMER_JOB_KEYS.filter((key) => key !== 'jobPriority');
const TIMER_JOB_KEY_SET: ReadonlySet = new Set(TIMER_JOB_KEYS);
-const DUE_DATE_KEYS: readonly string[] = ['dueDate', 'followUpDate'];
-const DUE_DATE_KEY_SET: ReadonlySet = new Set(DUE_DATE_KEYS);
+const DUE_DATE_KEY_SET: ReadonlySet = new Set(USER_TASK_DUE_DATE_KEYS);
/** Parsed with `Integer.parseInt`, at deployment or at task creation. */
const PRIORITY_ATTR_KEYS: ReadonlySet = new Set([
...engineSpellings('jobPriority'),
TASK_PRIORITY_KEY,
- USER_PRIORITY_KEY,
+ USER_TASK_PRIORITY_KEY,
]);
const RETRY_CYCLE_ATTR_KEYS: ReadonlySet = new Set(
@@ -312,7 +322,7 @@ const RETRY_CYCLE_ATTR_KEYS: ReadonlySet = new Set(
/** Parsed by the engine, so a bareword or number there is unreadable to it. */
const TEXT_ATTR_KEYS: ReadonlySet = new Set([
...RETRY_CYCLE_ATTR_KEYS,
- ...DUE_DATE_KEYS,
+ ...USER_TASK_DUE_DATE_KEYS,
]);
/**
@@ -441,28 +451,38 @@ const TASK_LISTENER_EVENT_SET: ReadonlySet = new Set(
* Read off the block rules so the message matches what is enforced; `attempt`
* has no row of its own.
*/
-export const PARAMETER_HOSTS_MESSAGE = `parameters belong on ${formatPlainWordList(
+export const PARAMETER_HOSTS_MESSAGE = `note: parameters belong on ${formatPlainWordList(
[...Object.values(ATTRIBUTE_BLOCK_RULES), ATTEMPT_BLOCK_RULE]
.filter((rule) => rule.parameters)
.map((rule) => rule.description),
'and',
-)}.`;
+)}`;
+
+const noParameterHostMessage = (description: string) =>
+ diagnosticText(
+ `${description} cannot declare an 'input' or 'output' parameter`,
+ PARAMETER_HOSTS_MESSAGE,
+ );
-export const REPEATED_OUTPUT_MESSAGE =
- "A repeated step cannot map an 'output' parameter: the engine refuses to " +
- 'deploy it (BpmnParse.checkActivityOutputParameterSupported). Move the ' +
- 'mapping to a step after the repetition.';
+export const REPEATED_OUTPUT_MESSAGE = diagnosticText(
+ "a repeated step cannot map an 'output' parameter",
+ 'note: the engine refuses to deploy an output mapping on a repeated step',
+ 'help: move the mapping to a step after the repetition',
+);
/** A listener has no row of its own, so it is added back. */
-const FIELD_HOSTS_MESSAGE = `an injected field belongs on ${Object.values(
+const FIELD_HOSTS_MESSAGE = `note: an injected field belongs on ${Object.values(
ATTRIBUTE_BLOCK_RULES,
)
.filter((rule) => rule.fields)
.map((rule) => rule.description)
- .join(', ')}, and on a listener.`;
+ .join(', ')}, and on a listener`;
export const noFieldHostMessage = (description: string) =>
- `${capitalize(description)} cannot declare a 'field' parameter; ${FIELD_HOSTS_MESSAGE}`;
+ diagnosticText(
+ `${description} cannot declare a 'field' parameter`,
+ FIELD_HOSTS_MESSAGE,
+ );
/**
* Names only the fieldless bindings written, since a listener takes neither
@@ -473,11 +493,12 @@ export const fieldBindingMessage = (
written: readonly string[],
takes: { keys: readonly string[]; targets: string },
) =>
- `${subject} carries an injected field only under a ${formatWordList(takes.keys)} ` +
- `binding: the engine injects into ${takes.targets} that binding names` +
- (written.length === 0
- ? '.'
- : `, and the binding written with ${formatWordList(written)} receives none.`);
+ diagnosticText(
+ `${subject} has a field but no ${formatWordList(takes.keys)} binding to inject it into`,
+ `note: the engine injects a field into ${takes.targets} that binding names`,
+ written.length > 0 &&
+ `note: the binding written with ${formatWordList(written)} receives no fields`,
+ );
export const ELEMENT_FIELD_BINDINGS = {
keys: FIELD_BINDING_KEYS,
@@ -500,84 +521,144 @@ const EXTERNAL_HOSTS_PHRASE = `${formatPlainWordList(
)} bound with 'topic'`;
export const noPropertyHostMessage = (description: string) =>
- `${capitalize(description)} cannot declare a 'property' line; a property line belongs on ${EXTERNAL_HOSTS_PHRASE}, and in a form field's block.`;
+ diagnosticText(
+ `${description} cannot declare a 'property' line`,
+ `note: a property line belongs on ${EXTERNAL_HOSTS_PHRASE}, and in a form field's block`,
+ );
export const noMappingHostMessage = (description: string) =>
- `${capitalize(description)} cannot map a reported failure; an 'error when ' line belongs on ${EXTERNAL_HOSTS_PHRASE}, whose external worker is what reports one.`;
+ diagnosticText(
+ `${description} cannot map a reported failure`,
+ `note: an 'error when ' line belongs on ${EXTERNAL_HOSTS_PHRASE}`,
+ 'note: only an external worker reports a failure',
+ );
export const topicBindingMessage = (
subject: string,
item: string,
written: readonly string[],
) =>
- `${subject} carries ${item} only under a 'topic' binding: the engine reads it for a step handed to an external worker` +
- (written.length === 0
- ? '.'
- : `, and the binding written with ${formatWordList(written)} hands the step to none.`);
+ diagnosticText(
+ `${subject} has ${item} but no 'topic' binding`,
+ `note: the engine reads ${item} only for a step handed to an external worker`,
+ written.length > 0 &&
+ `note: the binding written with ${formatWordList(written)} hands the step to no worker`,
+ );
/** `ExternalTaskEntity.evaluateThrowBpmnError` raises a BPMN error and nothing else. */
-export const MAPPING_HEAD_MESSAGE =
- 'An external task maps a reported failure onto an error and nothing else; ' +
- `write '${ERROR_MAPPING_HEAD} ${ERROR_MAPPING_WHEN} '.`;
+export const MAPPING_HEAD_MESSAGE = diagnosticText(
+ 'an external task maps a reported failure onto an error only',
+ `help: write '${ERROR_MAPPING_HEAD} ${ERROR_MAPPING_WHEN} '`,
+);
-export const MAPPING_WHEN_MESSAGE = `Write '${ERROR_MAPPING_WHEN}' between the code and the condition: '${ERROR_MAPPING_HEAD} ${ERROR_MAPPING_WHEN} '.`;
+export const MAPPING_WHEN_MESSAGE = diagnosticText(
+ `expected '${ERROR_MAPPING_WHEN}' between the error code and the condition`,
+ `help: write '${ERROR_MAPPING_HEAD} ${ERROR_MAPPING_WHEN} '`,
+);
export const priorityShapeMessage = (key: string) =>
- key === USER_PRIORITY_KEY
- ? `Setting '${key}' takes an integer or a "\${...}" expression; the engine parses a constant with Integer.parseInt when the task is created (TaskDecorator.initializeTaskPriority) and fails the instance on anything else.`
- : `Setting '${key}' takes an integer or a "\${...}" expression; the engine refuses to deploy a constant that is not an integer.`;
+ diagnosticText(
+ `setting '${key}' is not an integer or a "\${...}" expression`,
+ key === USER_TASK_PRIORITY_KEY
+ ? 'note: the engine parses a constant with Integer.parseInt when the task is created and fails the instance on anything else'
+ : 'note: the engine refuses to deploy a constant that is not an integer',
+ );
-export const VERSION_SHAPE_MESSAGE =
- `Setting 'version' takes a positive whole number, quoted or not, or a "\${...}" expression yielding one; ` +
- 'the engine parses the value as an integer when the step runs (BaseCallableElement.getVersion, TaskEntity.initializeFormRefFromTaskDefinition) and fails the instance on anything else.';
+export const VERSION_SHAPE_MESSAGE = diagnosticText(
+ `setting 'version' is not a positive whole number or a "\${...}" expression`,
+ 'note: the number may be quoted or not',
+ 'note: the engine parses the value as an integer when the step runs and fails the instance on anything else',
+);
export const dueDateShapeMessage = (key: string) =>
- `Setting '${key}' takes a period starting with 'P' or an ISO date-time such as "2026-01-01T09:00:00", or a "\${...}" expression; ` +
- 'the engine parses a constant with DueDateBusinessCalendar.resolveDuedate when the task is created and fails the instance on anything else.';
+ diagnosticText(
+ `setting '${key}' is not a period, a date-time, or a "\${...}" expression`,
+ 'note: the engine parses a constant when the task is created and fails the instance on anything else',
+ `help: write a period starting with 'P' such as "P3D", or an ISO date-time such as "2026-01-01T09:00:00"`,
+ );
-export const RETRY_CYCLE_SHAPE_MESSAGE =
- "Setting 'retryCycle' takes an ISO 8601 duration, an 'R/' repeat, or a comma " +
- 'list of durations; a single interval the engine cannot read is logged and dropped, so the ' +
- 'job keeps its default retries (ParseUtil.parseRetryIntervals), and a bad member of a list ' +
- 'is stored unchecked and, when its turn comes, drops that retry to the default strategy ' +
- 'with no wait (DefaultJobRetryCmd.execute).';
+export const RETRY_CYCLE_SHAPE_MESSAGE = diagnosticText(
+ "setting 'retryCycle' is not a duration, a repeat, or a list of durations",
+ 'note: the engine logs and drops a single interval it cannot read, so the job keeps its default retries',
+ 'note: a bad member of a list is stored unchecked, and when its turn comes that retry falls back to the default strategy with no wait',
+ `help: write an ISO 8601 duration such as "PT5M", an 'R/' repeat such as "R3/PT5M", or a comma list such as "PT1M,PT5M"`,
+);
export const resultVariableUnreadMessage = (binding: string) =>
- `Setting 'resultVariable' has no effect beside '${binding}': the engine hands it to an 'expression' binding alone (BpmnParse.parseServiceTaskLike), so nothing writes the variable.`;
+ diagnosticText(
+ `setting 'resultVariable' has no effect beside '${binding}'`,
+ "note: the engine hands it to an 'expression' binding only, so nothing writes the variable",
+ );
-export const MAP_DECISION_RESULT_UNREAD_MESSAGE =
- "Setting 'mapDecisionResult' has no effect without 'resultVariable': the engine applies the mapping only when storing the result into that variable (DecisionEvaluationUtil.evaluateDecision).";
+export const MAP_DECISION_RESULT_UNREAD_MESSAGE = diagnosticText(
+ "setting 'mapDecisionResult' has no effect without 'resultVariable'",
+ 'note: the engine applies the mapping only when it stores the result into that variable',
+);
export const decisionModifierMessage = (key: string) =>
- `Setting '${key}' stands only beside 'decision': the engine reads 'binding', 'version' and 'mapDecisionResult' on a step answering a decision table alone (BpmnParse.parseBusinessRuleTask).`;
+ diagnosticText(
+ `setting '${key}' has no 'decision' beside it`,
+ "note: the engine reads 'binding', 'version', and 'mapDecisionResult' only on a step that evaluates a decision table",
+ );
-export const HISTORY_TIME_TO_LIVE_MESSAGE =
- "Setting 'historyTimeToLive' takes a quoted number of days, 'PD' or ''; " +
- 'the engine reads the attribute as text, never as an expression, and refuses to deploy anything else (ParseUtil.parseHistoryTimeToLive).';
+export const HISTORY_TIME_TO_LIVE_MESSAGE = diagnosticText(
+ "setting 'historyTimeToLive' is not a quoted number of days",
+ 'note: the engine reads the attribute as text, never as an expression, and refuses to deploy anything else',
+ `help: write "PD" or ""`,
+);
-export const VERSION_TAG_LITERAL_MESSAGE =
- "Setting 'versionTag' takes a quoted string; the engine stores the tag as written, never evaluated (BpmnParse.parseProcess).";
+export const VERSION_TAG_LITERAL_MESSAGE = diagnosticText(
+ "setting 'versionTag' is not a quoted string",
+ 'note: the engine stores the tag as written and never evaluates it',
+);
-export const VERSION_TAG_LENGTH_MESSAGE = `Setting 'versionTag' is longer than ${VERSION_TAG_MAX_LENGTH} characters, the width of the column it is stored in (ACT_RE_PROCDEF.VERSION_TAG_), so the deployment fails.`;
+export const VERSION_TAG_LENGTH_MESSAGE = diagnosticText(
+ `setting 'versionTag' is longer than ${VERSION_TAG_MAX_LENGTH} characters`,
+ `note: the column the engine stores it in holds ${VERSION_TAG_MAX_LENGTH} characters, so the deployment fails`,
+);
export const candidateStarterMessage = (key: string) =>
- `Setting '${key}' takes ids as written: the engine stores each entry as a candidate identity link without evaluating it (BpmnDeployer.addAuthorizations), so a "\${...}" template names the id spelled by its text.`;
+ diagnosticText(
+ `setting '${key}' holds a "\${...}" template, which the engine never evaluates`,
+ 'note: the engine stores each entry as a candidate id as written, so the template text itself becomes the id',
+ );
export const headerLiteralMessage = (key: string) =>
- `Setting '${key}' takes a quoted string on a process header; the engine stores it as written, never evaluated (BpmnParse.parseProcess).`;
+ diagnosticText(
+ `setting '${key}' on a process header is not a quoted string`,
+ 'note: the engine stores it as written and never evaluates it',
+ );
export const runWithoutClauseMessage = (key: string, description: string) =>
- `Setting '${key}' is not valid on ${description} that does not repeat: it makes one job per run, so write a 'for' clause, or '${ENGINE_KEY_BY_RUN_KEY[key]}' for one job around the step.`;
+ diagnosticText(
+ `setting '${key}' is not valid on ${description} that does not repeat`,
+ 'note: it makes one job per run',
+ `help: write a 'for' clause, or '${ENGINE_KEY_BY_RUN_KEY[key]}' for one job around the step`,
+ );
-export const RUN_JOB_PRIORITY_MESSAGE = `Setting '${RUN_JOB_PRIORITY_KEY}' does not exist: Operaton reads a job priority off the step alone (BpmnParse.createActivityOnScope), so 'jobPriority' applies to every run's job.`;
+const CONDITION_ITEM_MESSAGE = `only '${VALUE_DOCUMENTATION_KEYS.condition}' can follow a condition inside its parentheses`;
-export const REPEAT_COUNT_MESSAGE =
- 'A repeat count must be a non-negative whole number, a variable, or a ' +
- '"${...}" expression yielding one; the engine reads a constant as text ' +
- 'with Integer.parseInt and truncates any other number with intValue() ' +
- '(MultiInstanceActivityBehavior.resolveLoopCardinality).';
+const CONDITION_DOCUMENTATION_KEY_MESSAGE = diagnosticText(
+ `'${DOCUMENTATION_KEY}' cannot document a condition`,
+ `help: write '${VALUE_DOCUMENTATION_KEYS.condition}'`,
+);
+
+const COUNT_DOCUMENTATION_MESSAGE = `setting '${VALUE_DOCUMENTATION_KEYS.count}' documents a count, but the 'for' clause has none`;
-export const TYPE_VALUE_MESSAGE = `Setting '${TYPE_BINDING_KEY}' must be ${formatWordList(TYPE_BINDING_VALUES)}.`;
+const EACH_DOCUMENTATION_MESSAGE = `setting '${VALUE_DOCUMENTATION_KEYS.each}' documents the name after 'each', but the 'for' clause has none`;
+
+export const RUN_JOB_PRIORITY_MESSAGE = diagnosticText(
+ `setting '${RUN_JOB_PRIORITY_KEY}' does not exist`,
+ "note: Operaton reads a job priority off the step only, so 'jobPriority' applies to every run's job",
+);
+
+export const REPEAT_COUNT_MESSAGE = diagnosticText(
+ 'the repeat count is not a non-negative whole number, a variable, or a "${...}" expression',
+ 'note: the engine reads a constant as text with Integer.parseInt',
+ 'note: the engine truncates any other number with intValue()',
+);
+
+export const TYPE_VALUE_MESSAGE = `setting '${TYPE_BINDING_KEY}' must be ${formatWordList(TYPE_BINDING_VALUES)}`;
const BUILTIN_BEHAVIOUR_CLASS: Readonly> = {
mail: 'MailActivityBehavior',
@@ -606,56 +687,83 @@ export const resultVariableBindingMessage = (
binding: string,
element: string,
) =>
- `${capitalize(description)} cannot carry 'resultVariable' beside '${binding}': the engine refuses to deploy it ('resultVariableName' not supported for ${element} elements using '${RESULT_VARIABLE_REFUSING_BINDINGS[binding]}'); bind with 'expression' to store the return value, or drop it.`;
+ diagnosticText(
+ `${description} cannot carry 'resultVariable' beside '${binding}'`,
+ `note: the engine refuses to deploy it with "'resultVariableName' not supported for ${element} elements using '${RESULT_VARIABLE_REFUSING_BINDINGS[binding]}'"`,
+ "help: bind with 'expression' to store the return value, or remove 'resultVariable'",
+ );
export const missingBuiltinFieldMessage = (
subject: string,
type: BuiltinTaskType,
group: RequiredFieldGroup,
) =>
- `${subject} binds ${TYPE_BINDING_KEY}: "${type}" without a ${formatWordList(group.names)} field; Operaton refuses to deploy it: "${group.error}" (BpmnParse.${BUILTIN_FIELD_VALIDATOR[type]}).`;
+ diagnosticText(
+ `${subject} binds ${TYPE_BINDING_KEY}: "${type}" without a ${formatWordList(group.names)} field`,
+ `note: Operaton refuses to deploy it with "${group.error}"`,
+ );
export const unknownBuiltinFieldMessage = (
name: string,
type: BuiltinTaskType,
) =>
- `Field '${name}' is not one a ${type} task takes; the engine sets it on ${BUILTIN_BEHAVIOUR_CLASS[type]}, which declares ${formatPlainWordList(BUILTIN_FIELD_NAMES[type], 'and')} (ClassDelegateUtil.applyFieldDeclaration).`;
+ diagnosticText(
+ `field '${name}' is not one a ${type} task takes`,
+ `note: the engine sets it on ${BUILTIN_BEHAVIOUR_CLASS[type]}, which declares ${formatPlainWordList(BUILTIN_FIELD_NAMES[type], 'and')}`,
+ );
export const shellFieldExpressionMessage = (name: string) =>
- `Field '${name}' on a shell task takes a quoted literal: Operaton reads every shell field as a fixed value (BpmnParse.validateFieldDeclarationsForShell) and fails the deployment on an expression.`;
+ diagnosticText(
+ `field '${name}' on a shell task is an expression`,
+ 'note: Operaton reads every shell field as a fixed value and fails the deployment on an expression',
+ 'help: write a quoted literal',
+ );
export const shellFlagValueMessage = (name: string) =>
- `Field '${name}' on a shell task takes "true" or "false"; the engine reads any other spelling as false (ShellActivityBehavior.readFields).`;
+ diagnosticText(
+ `field '${name}' on a shell task is not "true" or "false"`,
+ 'note: the engine reads any other spelling as false',
+ );
const SHELL_FLAG_LITERAL_SET: ReadonlySet = new Set(
SHELL_FLAG_LITERALS,
);
export const scriptListenerFieldMessage = (subject: string) =>
- `${subject} runs a fenced script, which the engine hands no field list; ` +
- `remove the script and bind the listener with ${formatWordList(LISTENER_FIELD_BINDING_KEYS)} ` +
- 'to inject one.';
+ diagnosticText(
+ `${subject} runs a fenced script, which the engine hands no field list`,
+ `help: remove the script and bind the listener with ${formatWordList(LISTENER_FIELD_BINDING_KEYS)} to inject one`,
+ );
export const fieldValueMessage = (name: string) =>
- `Field '${name}' takes a quoted string or a "\${...}" expression; ` +
- 'put the value in quotes.';
+ diagnosticText(
+ `field '${name}' is not a quoted string or a "\${...}" expression`,
+ 'help: put the value in quotes',
+ );
/**
* The opening decides the slot, so a literal opening with one can only reach
* the expression slot.
*/
export const escapedFieldLiteralMessage = (name: string) =>
- `Field '${name}' cannot carry quoted text opening with '\${' or '#{': the expression slot is picked by that opening, so the text would be evaluated rather than injected as written. Drop the backslash to write an expression.`;
+ diagnosticText(
+ `field '${name}' holds quoted text opening with '\${' or '#{'`,
+ 'note: that opening picks the expression slot, so the engine evaluates the text instead of injecting it as written',
+ 'help: drop the backslash to write an expression',
+ );
export const emptyFieldMessage = (name: string) =>
- `Field '${name}' cannot be empty: the engine reads an empty value as absent, so the ` +
- 'field declares neither a fixed value nor an expression and the deployment fails ' +
- `(BpmnParse.parseFieldDeclaration). Write '\${""}' for an actual empty string.`;
+ diagnosticText(
+ `field '${name}' is empty`,
+ 'note: the engine reads an empty value as absent, so the field declares neither a fixed value nor an expression and the deployment fails',
+ `help: write '\${""}' for an actual empty string`,
+ );
-export const EMPTY_STRING_VALUE_MESSAGE =
- 'An empty or blank string writes no value at all: the engine trims it and ' +
- 'reads it as absent rather than as an empty string (BpmnParseUtil.getElValueProvider). ' +
- 'Write \'${""}\' for an actual empty string.';
+export const EMPTY_STRING_VALUE_MESSAGE = diagnosticText(
+ 'an empty or blank string writes no value',
+ 'note: the engine trims it and reads it as absent, not as an empty string',
+ `help: write '\${""}' for an actual empty string`,
+);
const JUEL_RESERVED_WORD_SET: ReadonlySet = new Set(
JUEL_RESERVED_WORDS,
@@ -667,11 +775,18 @@ const JUEL_RAW_TEMPLATE_WORD_SET: ReadonlySet = new Set([
]);
export const juelKeywordMessage = (word: string, key: string) =>
- `'${word}' is a JUEL keyword (Scanner.addKeyToken), so the engine refuses any expression naming it. Reach the variable through a string key instead: "\${${key}}".`;
+ diagnosticText(
+ `'${word}' is a JUEL keyword, so the engine refuses any expression naming it`,
+ `help: reach the variable through a string key: "\${${key}}"`,
+ );
/** `Character.isJavaIdentifierPart('-')` is false, so the identifier ends at the hyphen. */
export const hyphenNameMessage = (name: string, key: string) =>
- `'${name}' carries a hyphen, which JUEL scans as a minus (Scanner.nextIdentifier), so the engine reads a subtraction. Reach the variable through a string key instead: "\${${key}}".`;
+ diagnosticText(
+ `'${name}' contains a hyphen, which JUEL reads as a minus`,
+ 'note: the engine evaluates a subtraction instead of reading the variable',
+ `help: reach the variable through a string key: "\${${key}}"`,
+ );
type ConditionSlot = 'condition' | 'until';
@@ -680,11 +795,27 @@ export const nonBooleanConditionMessage = (
slot: ConditionSlot,
) =>
slot === 'until'
- ? `An 'until' condition must be boolean, but this one is ${shape}: the engine throws when a completion condition evaluates to anything else (MultiInstanceActivityBehavior.completionConditionSatisfied).`
- : `A condition must be boolean, but this one is ${shape}: the engine throws 'condition expression returns ${shape === 'null' ? 'null' : 'non-Boolean'}' when it evaluates it (UelExpressionCondition.evaluate).`;
+ ? diagnosticText(
+ `the 'until' condition must be boolean, but it is ${shape}`,
+ 'note: the engine throws when a completion condition evaluates to anything else',
+ )
+ : diagnosticText(
+ `the condition must be boolean, but it is ${shape}`,
+ `note: the engine throws 'condition expression returns ${shape === 'null' ? 'null' : 'non-Boolean'}' when it evaluates it`,
+ );
-export const COMPOSITE_OPERAND_MESSAGE =
- "A composite template cannot be spliced into the surrounding expression: JUEL has no '${' token once inside an expression (Scanner.nextEval), so only a raw that is exactly one '${...}' with no '}' outside a string literal in its body can be an operand. Write the whole expression as one raw template instead.";
+export const COMPOSITE_OPERAND_MESSAGE = diagnosticText(
+ 'a composite template cannot be an operand of the surrounding expression',
+ "note: JUEL has no '${' token inside an expression",
+ "note: only a raw that is exactly one '${...}' with no '}' outside a string literal in its body can be an operand",
+ 'help: write the whole expression as one raw template',
+);
+
+export const NESTED_TEMPLATE_MESSAGE = diagnosticText(
+ "a '${...}' template holds another '${' inside it",
+ "note: JUEL has no '${' token inside an expression, so the engine cannot parse it",
+ 'help: close the template before any text around it, as in "1${x}"',
+);
const EL_BINDING_KEYS: ReadonlySet = new Set([
'expression',
@@ -709,142 +840,218 @@ const EMPTY_BINDING_NOUN: Readonly> = {
};
export const literalElBindingMessage = (key: string) =>
- `Setting '${key}' takes a "\${...}" template or a bare name, never quoted text: ` +
- (key === 'expression'
- ? 'the string evaluates to itself and runs nothing'
- : 'a string resolves to no delegate to run') +
- `. Write '${key}: "\${...}"' or '${key}: '.`;
+ diagnosticText(
+ `setting '${key}' is quoted text, not a "\${...}" template or a bare name`,
+ key === 'expression'
+ ? 'note: the string evaluates to itself and runs nothing'
+ : 'note: a string resolves to no delegate to run',
+ `help: write '${key}: "\${...}"' or '${key}: '`,
+ );
export const templateAsClassMessage = (key: string, alternative: string) =>
- `Setting '${key}' takes a class name, loaded as written (ClassDelegateUtil.instantiateDelegate); a "\${...}" template there is not evaluated. Write '${key}: com.example.X', or '${alternative}: "\${bean}"' to resolve one at runtime.`;
+ diagnosticText(
+ `setting '${key}' holds a "\${...}" template, but the engine loads a class name as written`,
+ 'note: the template is never evaluated',
+ `help: write '${key}: com.example.X', or '${alternative}: "\${bean}"' to resolve one at runtime`,
+ );
/**
* The engine refuses a blank `class`, `expression` or `delegateExpression` at
- * deployment; the other keys deploy blank and fail at the step.
+ * deployment; the other keys deploy blank and fail at the step. Quoted text is
+ * a valid JUEL expression evaluating to itself, so on `expression` it deploys
+ * and runs as a no-op, while a delegate resolving to a string fails the step.
*/
-function bindingValueMessage(key: string, value: Expr): string | undefined {
+function bindingValueMessage(
+ key: string,
+ value: Expr,
+): ['error' | 'warning', string] | undefined {
const noun = EMPTY_BINDING_NOUN[key];
if (noun === undefined) return undefined;
if (isLiteralString(value)) {
if (value.value.trim().length === 0) {
- return `Setting '${key}' cannot be empty; name the ${noun}.`;
+ return [
+ 'error',
+ diagnosticText(`setting '${key}' is empty`, `help: name the ${noun}`),
+ ];
}
- return EL_BINDING_KEYS.has(key) ? literalElBindingMessage(key) : undefined;
+ if (!EL_BINDING_KEYS.has(key)) return undefined;
+ return [
+ key === 'expression' ? 'warning' : 'error',
+ literalElBindingMessage(key),
+ ];
}
const alternative = CLASS_BINDING_ALTERNATIVE[key];
return isRawExpr(value) && alternative !== undefined
- ? templateAsClassMessage(key, alternative)
+ ? ['error', templateAsClassMessage(key, alternative)]
: undefined;
}
export const unknownDirectionMessage = (
word: string,
legal: readonly string[],
-) => `Unknown parameter direction '${word}'; write ${formatWordList(legal)}.`;
+) =>
+ diagnosticText(
+ `unknown parameter direction '${word}'`,
+ `help: write ${formatWordList(legal)}`,
+ );
-export const FORM_KEY_AND_REF_MESSAGE =
- "A user task names its form with 'formKey' or with 'formRef', never both; " +
- 'the engine refuses to deploy a task carrying the two.';
+export const FORM_KEY_AND_REF_MESSAGE = diagnosticText(
+ "a user task names its form with both 'formKey' and 'formRef'",
+ 'note: the engine refuses to deploy a task carrying the two',
+);
const BINDING_MODE_PHRASES: readonly string[] = CALL_BINDING_VALUES.map(
(value) => `'binding: ${value}'`,
);
-export const FORM_REF_BINDING_MESSAGE = `A 'formRef' needs the binding resolving it: add ${formatPlainWordList(
- [...BINDING_MODE_PHRASES, "'version: '"],
-)}. The engine refuses to deploy a form reference with none.`;
+export const FORM_REF_BINDING_MESSAGE = diagnosticText(
+ "'formRef' has no binding resolving it",
+ 'note: the engine refuses to deploy a form reference with none',
+ `help: add ${formatPlainWordList([...BINDING_MODE_PHRASES, "'version: '"])}`,
+);
-export const FORM_REF_MISSING_MESSAGE =
- "'binding' and 'version' pin which deployed version of a form the engine " +
- "resolves, so neither stands without a 'formRef'.";
+export const FORM_REF_MISSING_MESSAGE = diagnosticText(
+ "'binding' and 'version' have no 'formRef' to pin",
+ 'note: they pin which deployed version of a form the engine resolves',
+);
export const formFieldSettingsOnlyMessage = (id: string, text: string) =>
- `Form field '${id}' takes 'key: value' settings in its parens; '${text}' is not one.`;
+ `'${text}' in form field '${id}' is not a 'key: value' setting`;
export const unknownFormFieldSettingMessage = (id: string, key: string) =>
- `Unknown form field setting '${key}' on '${id}'; write ${formatWordList(FORM_FIELD_SETTING_KEYS)}.`;
+ diagnosticText(
+ `unknown form field setting '${key}' on '${id}'`,
+ `help: write ${formatWordList(FORM_FIELD_SETTING_KEYS)}`,
+ );
export const constraintMisfitMessage = (
name: string,
field: FormField,
fits: readonly string[],
) =>
- `Constraint '${name}' fits a ${formatPlainWordList(fits)} field, not the ${field.type} field '${field.id}': the engine checks a submitted ${formatPlainWordList(fits)} alone and fails every other submission.`;
+ diagnosticText(
+ `constraint '${name}' does not fit the ${field.type} field '${field.id}'`,
+ `note: it fits a ${formatPlainWordList(fits)} field`,
+ `note: the engine checks a submitted ${formatPlainWordList(fits)} only and fails every other submission`,
+ );
export const patternMisfitMessage = (field: FormField) =>
- `Setting 'pattern' is the date pattern a 'date' field is parsed with; '${field.id}' is a ${field.type} field, which the engine reads no pattern off.`;
+ diagnosticText(
+ `setting 'pattern' does not fit the ${field.type} field '${field.id}'`,
+ "note: 'pattern' is the date pattern a 'date' field is parsed with",
+ `note: the engine reads no pattern off a ${field.type} field`,
+ );
export const flagFalseMessage = (key: string) =>
- `A field is ${key} only while the setting is written, so '${key}: false' says nothing; leave the setting out.`;
+ diagnosticText(
+ `'${key}: false' says nothing`,
+ `note: a field is ${key} only while the setting is written`,
+ 'help: leave the setting out',
+ );
export const booleanShapeMessage = (key: string) =>
- `Setting '${key}' takes an unquoted boolean; write '${key}: true' or '${key}: false'.`;
+ diagnosticText(
+ `setting '${key}' is not an unquoted boolean`,
+ `help: write '${key}: true' or '${key}: false'`,
+ );
export const flagNotTrueMessage = (key: string) =>
- `Setting '${key}' takes the literal true; write '${key}: true'.`;
+ diagnosticText(
+ `setting '${key}' is not the literal true`,
+ `help: write '${key}: true'`,
+ );
export const integerBoundMessage = (key: string) =>
- `Setting '${key}' takes an integer literal or a quoted integer such as "-5".`;
+ diagnosticText(
+ `setting '${key}' is not an integer`,
+ 'help: write an integer literal or a quoted integer such as "-5"',
+ );
-export const PATTERN_VALUE_MESSAGE = `Setting 'pattern' takes a non-empty quoted date pattern such as "dd/MM/yyyy".`;
+export const PATTERN_VALUE_MESSAGE = diagnosticText(
+ "setting 'pattern' is not a non-empty quoted date pattern",
+ 'help: write a pattern such as "dd/MM/yyyy"',
+);
-export const PATTERN_LETTERS_MESSAGE =
- "Setting 'pattern' may hold only SimpleDateFormat letters " +
- '(G, y, Y, M, L, w, W, D, d, F, E, u, a, H, k, K, h, m, s, S, z, Z, X), ' +
- 'quoted literal runs, and non-letters; the engine builds a java.text.SimpleDateFormat ' +
- 'from it and throws on any other letter (DateFormType).';
+export const PATTERN_LETTERS_MESSAGE = diagnosticText(
+ "setting 'pattern' holds a letter SimpleDateFormat does not read",
+ 'note: a pattern holds only the letters G, y, Y, M, L, w, W, D, d, F, E, u, a, H, k, K, h, m, s, S, z, Z, and X, quoted literal runs, and non-letters',
+ 'note: the engine builds a java.text.SimpleDateFormat from it and throws on any other letter',
+);
-export const VALIDATOR_EMPTY_MESSAGE =
- "Setting 'validator' cannot be empty; name the class or the expression it " +
- 'resolves (FormValidators.createValidator).';
+export const VALIDATOR_EMPTY_MESSAGE = diagnosticText(
+ "setting 'validator' is empty",
+ 'help: name the class or the expression it resolves',
+);
export const valuesOnNonEnumMessage = (field: FormField) =>
- `Value lines belong on an 'enum' field; '${field.id}' is a ${field.type} field.`;
+ diagnosticText(
+ `the ${field.type} field '${field.id}' cannot take value lines`,
+ "note: value lines belong on an 'enum' field",
+ );
export const emptyEnumMessage = (id: string) =>
- `Enum field '${id}' offers no values, so the engine rejects every submitted value; add a value line such as 'basic "Basic"'.`;
+ diagnosticText(
+ `enum field '${id}' offers no values`,
+ 'note: the engine rejects every submitted value',
+ `help: add a value line such as 'basic "Basic"'`,
+ );
-export const duplicateValueMessage = (id: string) => `Duplicate value '${id}'.`;
+export const duplicateValueMessage = (id: string) => `duplicate value '${id}'`;
-/** The default is converted on every render, so it deploys and the form never opens. */
export const enumDefaultMessage = (
id: string,
value: string,
ids: readonly string[],
) =>
- `The default "${value}" of enum field '${id}' names none of its values; write ${formatWordList(ids)}.`;
+ diagnosticText(
+ `the default "${value}" of enum field '${id}' names none of its values`,
+ 'note: the engine converts the default every time the form renders, so the form never opens',
+ `help: write ${formatWordList(ids)}`,
+ );
export const numberDefaultMessage = (id: string, text: string) =>
- `The default ${text} of number field '${id}' is not an integer; the engine ` +
- 'converts it with Long.valueOf every time the form renders (LongFormType.convertValue) ' +
- 'and throws on anything else.';
+ diagnosticText(
+ `the default ${text} of number field '${id}' is not an integer`,
+ 'note: the engine converts it with Long.valueOf every time the form renders and throws on anything else',
+ );
export const booleanDefaultMessage = (id: string, text: string) =>
- `The default ${text} of boolean field '${id}' is not "true" or "false"; the engine ` +
- 'reads any other spelling as false (BooleanFormType.convertValue).';
+ diagnosticText(
+ `the default ${text} of boolean field '${id}' is not "true" or "false"`,
+ 'note: the engine reads any other spelling as false',
+ );
/** An ISO date reads as legal to a human and fails the engine's own pattern. */
export const isoDateDefaultMessage = (id: string, value: string) =>
- `The default "${value}" of date field '${id}' is an ISO date, but the engine's default ` +
- 'pattern is "dd/MM/yyyy" (ProcessEngineConfigurationImpl.initFormTypes); add a \'pattern\' ' +
- 'setting, or write the date to fit it.';
+ diagnosticText(
+ `the default "${value}" of date field '${id}' is an ISO date, which the engine's default pattern does not read`,
+ 'note: the default pattern is "dd/MM/yyyy"',
+ "help: add a 'pattern' setting, or write the date to fit the default pattern",
+ );
export const formFieldDirectionMessage = (
id: string,
direction: string,
isEnum: boolean,
) =>
- `Unknown member direction '${direction}' in form field '${id}': its block takes 'property = ""' lines${isEnum ? ' and value lines' : ''}.`;
+ diagnosticText(
+ `unknown member direction '${direction}' in form field '${id}'`,
+ `note: its block takes 'property = ""' lines${isEnum ? ' and value lines' : ''}`,
+ );
export const propertyValueMessage = (name: string) =>
- `Property '${name}' takes a quoted string or a "\${...}" expression; ` +
- 'put the value in quotes.';
+ diagnosticText(
+ `property '${name}' is not a quoted string or a "\${...}" expression`,
+ 'help: put the value in quotes',
+ );
const isQuotedMatching = (value: Expr | undefined, shape: RegExp): boolean =>
isLiteralString(value) && shape.test(value.value);
+/** An integer literal, or quoted text holding one. */
const isIntegerValue = (value: Expr | undefined): boolean =>
- value !== undefined && integerLiteralText(value) !== undefined;
+ (value !== undefined && integerLiteralText(value) !== undefined) ||
+ isQuotedMatching(value, FORM_BOUND_TEXT);
type ValueShapeRule = (
key: string,
@@ -863,9 +1070,7 @@ const unquotedBoolean: ValueShapeRule = (key, value) =>
isLiteralBool(value) ? undefined : booleanShapeMessage(key);
const integer: ValueShapeRule = (key, value) =>
- isIntegerValue(value) || isQuotedMatching(value, FORM_BOUND_TEXT)
- ? undefined
- : integerBoundMessage(key);
+ isIntegerValue(value) ? undefined : integerBoundMessage(key);
/** A blank literal is the one shape `FormValidators.createValidator` refuses to deploy. */
const nonEmptyText: ValueShapeRule = (_key, value) =>
@@ -931,48 +1136,51 @@ const PROCESS_HEADER_VALUE_RULES: Readonly> = {
};
function particleOnlyMessage(subject: string): string {
- return `Only ${subject} takes a particle.`;
+ return `only ${subject} takes a particle`;
}
function nameRequiredMessage(subject: string, kind: string): string {
- return `${subject} needs the ${kind}'s name: the engine matches ${kind}s by name.`;
+ return diagnosticText(
+ `${subject} has no ${kind} name`,
+ `note: the engine matches ${kind}s by name`,
+ );
}
-const TIMER_PAYLOAD_PREFIX =
- 'A timer needs to know how to read the time: write ';
+const TIMER_PAYLOAD_HEADLINE = 'the timer does not say when it fires';
-export const TIMER_PAYLOAD_MESSAGE =
- TIMER_PAYLOAD_PREFIX +
- `'timer("PT1H")', 'timer(at: "2026-08-01T09:00:00")', or ` +
- `'timer(every: "R/PT10M")'.`;
+export const TIMER_PAYLOAD_MESSAGE = diagnosticText(
+ TIMER_PAYLOAD_HEADLINE,
+ `help: write 'timer("PT1H")', 'timer(at: "2026-08-01T09:00:00")', or 'timer(every: "R/PT10M")'`,
+);
-export const LISTENER_TIMER_PAYLOAD_MESSAGE =
- TIMER_PAYLOAD_PREFIX +
- `'after "PT1H"', 'at "2026-08-01T09:00:00"', or 'every "R/PT10M"'.`;
+export const LISTENER_TIMER_PAYLOAD_MESSAGE = diagnosticText(
+ TIMER_PAYLOAD_HEADLINE,
+ `help: write 'after "PT1H"', 'at "2026-08-01T09:00:00"', or 'every "R/PT10M"'`,
+);
-const timerShapeMessage = (
- particle: string,
- expected: string,
- calendar: string,
-) =>
- `'${particle}' takes ${expected}; the engine reads it as text and fails when it does not fit (${calendar}).`;
+const timerShapeMessage = (particle: string, noun: string, help: string) =>
+ diagnosticText(
+ `this '${particle}' time is not ${noun}`,
+ 'note: the engine reads it as text and fails when it does not fit',
+ `help: write ${help}`,
+ );
export const AFTER_SHAPE_MESSAGE = timerShapeMessage(
'after',
- 'an ISO 8601 duration such as "PT1H", on its own or beside a start or end date-time ("2026-01-01T00:00:00/PT1H", "PT1H/2026-12-31T00:00:00")',
- 'DurationBusinessCalendar.resolveDuedate',
+ 'an ISO 8601 duration',
+ 'a duration such as "PT1H", on its own or beside a start or end date-time such as "2026-01-01T00:00:00/PT1H" or "PT1H/2026-12-31T00:00:00"',
);
export const AT_SHAPE_MESSAGE = timerShapeMessage(
'at',
- 'an ISO date-time such as "2026-08-01T09:00:00", or a duration counted from now',
- 'DueDateBusinessCalendar.resolveDuedate',
+ 'an ISO date-time or a duration',
+ 'a date-time such as "2026-08-01T09:00:00", or a duration counted from now such as "P1D"',
);
export const EVERY_SHAPE_MESSAGE = timerShapeMessage(
'every',
- 'an ISO 8601 repeat such as "R/PT10M", or a six-field cron expression or one of its nicknames such as "@daily"',
- 'CycleBusinessCalendar.resolveDuedate',
+ 'an ISO 8601 repeat or a cron expression',
+ 'a repeat such as "R/PT10M", or a six-field cron expression or one of its nicknames such as "@daily"',
);
const TIMER_SHAPE_BY_PARTICLE: Readonly<
@@ -984,242 +1192,366 @@ const TIMER_SHAPE_BY_PARTICLE: Readonly<
};
/** `only` omits the name slot, which an author who wrote none should not see as a placeholder. */
-const CONDITION_PHRASING = {
+const PAYLOAD_PHRASING = {
handler: {
- subject: 'A condition handler',
+ subject: 'a condition handler',
clause: 'on condition',
only: "'on condition'",
+ timer: "'on timer'",
},
catch: {
- subject: 'An awaited condition',
+ subject: 'an awaited condition',
clause: 'await condition',
only: "'await condition'",
+ timer: "'await timer'",
},
start: {
- subject: 'A condition start',
+ subject: 'a condition start',
clause: 'start S condition',
only: 'a condition start',
+ timer: 'a timer start',
},
} as const;
-type ConditionPosition = keyof typeof CONDITION_PHRASING;
+type PayloadPosition = keyof typeof PAYLOAD_PHRASING;
+
+export const SECOND_PAREN_VALUE_MESSAGE = diagnosticText(
+ 'a second unkeyed value in the parens names nothing',
+ 'note: the parens carry one unkeyed value, the payload, and a second one never reaches the engine',
+ "help: write it as a 'key: value' setting, or remove it",
+);
+
+export const COMPENSATE_TYPO_MESSAGE = diagnosticText(
+ "unknown event kind 'compensate'",
+ "help: write 'compensation'",
+);
+
+export const CONDITIONAL_TYPO_MESSAGE = diagnosticText(
+ "unknown event kind 'conditional'",
+ "help: write 'condition'",
+);
+
+export const PARALLEL_SECOND_ELSE_MESSAGE = diagnosticText(
+ "a 'parallel' statement has a second 'else' branch",
+ "note: the first 'else' already runs when no condition held",
+ 'help: fold this branch into it, or give it a condition',
+);
+
+export const PARALLEL_ELSE_WITHOUT_CONDITION_MESSAGE = diagnosticText(
+ "this 'else' branch has no sibling with a condition to fall back from",
+ 'note: with no condition anywhere, every branch runs',
+ "help: give a sibling a condition, or remove the 'else'",
+);
+
+export const PARALLEL_ELSE_BESIDE_UNCONDITIONED_MESSAGE = diagnosticText(
+ "this 'else' branch can never run",
+ "note: an 'else' runs only when no sibling branch was taken, and a branch with no condition is always taken",
+ "help: give every sibling a condition, or remove the 'else'",
+);
-export const SECOND_PAREN_VALUE_MESSAGE =
- 'The parens carry one unkeyed value, the payload; a second one names ' +
- "nothing and never reaches the engine. Write it as a 'key: value' setting, " +
- 'or remove it.';
+export const elseFailWordMessage = (word: string): string =>
+ diagnosticText(
+ `unknown word '${word}' after 'else'`,
+ `note: 'else' takes a block, or '${ELSE_FAIL_WORD}' to stop the run with an error when no condition holds`,
+ );
-export const COMPENSATE_TYPO_MESSAGE =
- "Unknown event kind 'compensate'; write 'compensation'.";
+export const ELSE_FAIL_WITHOUT_CONDITION_MESSAGE = diagnosticText(
+ `'else ${ELSE_FAIL_WORD}' has no branch with a condition to fail from`,
+ 'note: with no condition anywhere, every branch runs',
+ `help: give a branch a condition, or remove 'else ${ELSE_FAIL_WORD}'`,
+);
-export const CONDITIONAL_TYPO_MESSAGE = `Unknown event kind 'conditional'; did you mean 'condition'?`;
+export const ELSE_FAIL_BESIDE_UNCONDITIONED_MESSAGE = diagnosticText(
+ `'else ${ELSE_FAIL_WORD}' can never happen`,
+ 'note: a branch with no condition is always taken, so the run never finds no branch to take',
+ `help: give every branch a condition, or remove 'else ${ELSE_FAIL_WORD}'`,
+);
-export const PARALLEL_SECOND_ELSE_MESSAGE =
- "A 'parallel' statement takes one 'else' branch at most; the first one " +
- 'already runs when no condition held. Fold this branch into it or give it a ' +
- 'condition.';
+export const ELSE_FAIL_BESIDE_ELSE_MESSAGE = diagnosticText(
+ `'else ${ELSE_FAIL_WORD}' can never happen beside an 'else' branch`,
+ "note: the 'else' branch runs whenever no condition holds",
+ 'help: remove one of the two',
+);
-export const PARALLEL_ELSE_WITHOUT_CONDITION_MESSAGE =
- "An 'else' branch needs a sibling branch with a condition: with no condition " +
- 'anywhere every branch runs, so there is nothing to fall back from. Give a ' +
- "sibling a condition, or drop the 'else'.";
+export const START_TRIGGER_IN_HANDLER_MESSAGE = diagnosticText(
+ 'the start of an event-handler body cannot carry a trigger',
+ "note: the handler's own 'on ' is what it catches",
+);
-export const PARALLEL_ELSE_BESIDE_UNCONDITIONED_MESSAGE =
- "An 'else' branch runs only when no sibling branch was taken, and a branch " +
- 'with no condition is always taken, so this one could never run. Give every ' +
- "sibling a condition, or drop the 'else'.";
+export const NESTED_START_FORM_MESSAGE = diagnosticText(
+ 'a start inside a subprocess, attempt block, or handler body cannot take a form',
+ "note: the engine reads a start form off the process's own start only, so this form is never shown",
+);
-export const START_TRIGGER_IN_HANDLER_MESSAGE =
- "The start of an event-handler body carries no trigger; the handler's own " +
- "'on ' is what it catches.";
+export const NESTED_START_INITIATOR_MESSAGE = diagnosticText(
+ "a start inside a subprocess, attempt block, or handler body cannot take 'initiator'",
+ "note: the engine reads it off the process's own start only, so nothing is written",
+);
-export const NESTED_START_FORM_MESSAGE =
- 'A start inside a subprocess, attempt block, or handler body takes no ' +
- "form: the engine reads a start form off the process's own start alone " +
- '(BpmnParse.parseStartFormHandlers) and BpmnParse.parseScopeStartEvent ' +
- 'reads none, so this form is never shown.';
+const SECOND_DEFAULT_START_HEADLINE =
+ "this is the process's second plain or timer start";
-export const NESTED_START_INITIATOR_MESSAGE =
- 'A start inside a subprocess, attempt block, or handler body takes no ' +
- "'initiator': the engine reads it off the process's own start alone " +
- '(BpmnParse.parseProcessDefinitionStartEvent) and ' +
- 'BpmnParse.parseScopeStartEvent reads none, so nothing is written.';
+const SECOND_DEFAULT_START_REFUSAL =
+ 'note: Operaton refuses a second one, so the deployment fails';
-export const SECOND_DEFAULT_START_MESSAGE =
- 'A process takes one plain or timer start: Operaton refuses a second one ' +
- '(BpmnParse.selectInitial), so the deployment fails. Keep one, or give ' +
- 'this start a message, signal, or condition trigger.';
+export const SECOND_DEFAULT_START_MESSAGE = diagnosticText(
+ SECOND_DEFAULT_START_HEADLINE,
+ SECOND_DEFAULT_START_REFUSAL,
+ 'help: keep one, or give this start a message, signal, or condition trigger',
+);
-export const START_AFTER_IMPLICIT_START_MESSAGE =
- 'A body that does not open with a start gets a plain start of its own, ' +
- "so this is the process's second plain or timer start, which Operaton " +
- 'refuses (BpmnParse.selectInitial), so the deployment fails. Open the ' +
- 'body with this start, or give it a message, signal, or condition trigger.';
+export const START_AFTER_IMPLICIT_START_MESSAGE = diagnosticText(
+ SECOND_DEFAULT_START_HEADLINE,
+ 'note: a body that does not open with a start gets a plain start of its own',
+ SECOND_DEFAULT_START_REFUSAL,
+ 'help: open the body with this start, or give it a message, signal, or condition trigger',
+);
export function duplicateNamedStartMessage(
trigger: string,
name: string,
): string {
- return `Another start already subscribes to ${trigger} '${name}': Operaton keeps one ${trigger} start subscription per name and process (BpmnParse.addEventSubscriptionDeclaration), so the deployment fails.`;
+ return diagnosticText(
+ `another start already subscribes to ${trigger} '${name}'`,
+ `note: Operaton keeps one ${trigger} start subscription per name and process, so the deployment fails`,
+ );
}
export function duplicateConditionStartMessage(text: string): string {
- return `Another start already carries the condition '${text}': Operaton keeps one conditional start per condition text and process (BpmnParse.addEventSubscriptionDeclaration), so the deployment fails.`;
+ return diagnosticText(
+ `another start already carries the condition '${text}'`,
+ 'note: Operaton keeps one conditional start per condition text and process, so the deployment fails',
+ );
}
export function timerJobKeyTwiceMessage(key: string): string {
- return `Setting '${key}' is already written on the 'on timer' head, and both land on this start event, the element the engine reads the timer job's settings from (BpmnParse.parseTimer, DefaultFailedJobParseListener.parseStartEvent); keep one.`;
+ return diagnosticText(
+ `setting '${key}' is already written on the 'on timer' head`,
+ "note: both land on this start event, the element the engine reads the timer job's settings from",
+ 'help: keep one',
+ );
}
export function raceDuplicateMessage(trigger: string, name: string): string {
- return `Another branch of this 'await' already catches ${trigger} '${name}': every branch subscribes on the gateway's own scope (BpmnParse.parseIntermediateCatchEvent), which keeps one ${trigger} subscription per name (BpmnParse.addEventSubscriptionDeclaration), so the deployment fails.`;
+ return diagnosticText(
+ `another branch of this 'await' already catches ${trigger} '${name}'`,
+ `note: every branch subscribes on the gateway's own scope, which keeps one ${trigger} subscription per name, so the deployment fails`,
+ );
}
-export const DEAD_LOOP_MESSAGE =
- "This loop can never repeat: every path through the 'do' body ends or redirects the flow, so the condition is never evaluated and the loop gateway would lower to a disconnected node with no incoming flow, which is invalid BPMN. End after the loop, or keep one path through the body.";
+export const DEAD_LOOP_MESSAGE = diagnosticText(
+ 'this loop can never repeat',
+ "note: every path through the 'do' body ends or redirects the flow, so the condition is never evaluated",
+ 'note: the loop gateway would have no incoming flow, which is invalid BPMN',
+ 'help: end after the loop, or keep one path through the body',
+);
+
+const UNREACHABLE_MESSAGE = diagnosticText(
+ 'this step can never run',
+ "note: an earlier 'end', 'throw', 'goto', 'emit link', or an 'if', 'parallel', or 'await' whose every branch ends always ends or redirects the flow before it",
+ 'note: the step would have no incoming flow, which is invalid BPMN',
+);
export function emptyLoopBodyMessage(keyword: string): string {
- return `The '${keyword}' body has no steps, so the loop and its condition would be dropped: with nothing to loop over, the gateway keeps only its exit and the condition is never written. Put a step in the body, or remove the loop.`;
+ return diagnosticText(
+ `the '${keyword}' body has no steps`,
+ 'note: with nothing to loop over, the loop and its condition are dropped',
+ 'help: put a step in the body, or remove the loop',
+ );
}
export function blockMemberMessage(what: string, verb: string): string {
- return `${what} written inside a body belongs to nothing and is dropped: put it in the attribute block of the element it ${verb}, the braces before that element's body.`;
+ return diagnosticText(
+ `${what} written inside a body belongs to nothing and is dropped`,
+ `help: put it in the attribute block of the element it ${verb}, the braces before that element's body`,
+ );
}
-const END_TRIGGERS_MESSAGE =
- "An end event carries 'terminate', which stops every running path in this " +
- `scope, or 'cancel', which gives up the 'attempt' block it sits in.`;
-
-export const END_TIMER_MESSAGE =
- 'A timer cannot end a process; a timer is something a process waits on. ' +
- `Write 'await timer("PT1H")' to pause the flow here, ` +
- `'on timer("PT1H")' to react while the surrounding steps run, or ` +
- `'on : timer("PT1H")' to watch only while that step runs. ` +
- END_TRIGGERS_MESSAGE;
-
-export const END_CONDITION_MESSAGE =
- 'A condition cannot end a process; a condition is something a process ' +
- `waits on. Write 'await condition(amount > 100)' to pause the flow ` +
- `here, 'on condition(amount > 100)' to react while the surrounding ` +
- `steps run, or 'on : condition(amount > 100)' to watch only ` +
- 'while that step runs. ' +
- END_TRIGGERS_MESSAGE;
+const END_TRIGGERS_NOTE =
+ "note: an end event carries 'terminate', which stops every running path in this " +
+ "scope, or 'cancel', which gives up the 'attempt' block it sits in";
+
+const endWaitMessage = (kind: string, payload: string) =>
+ diagnosticText(
+ `a ${kind} cannot end a process`,
+ `note: a ${kind} is something a process waits on`,
+ END_TRIGGERS_NOTE,
+ `help: write 'await ${kind}${payload}' to pause the flow here`,
+ `help: write 'on ${kind}${payload}' to react while the surrounding steps run`,
+ `help: write 'on : ${kind}${payload}' to watch only while that step runs`,
+ );
+
+export const END_TIMER_MESSAGE = endWaitMessage('timer', '("PT1H")');
+
+export const END_CONDITION_MESSAGE = endWaitMessage(
+ 'condition',
+ '(amount > 100)',
+);
export const END_TRIGGER_NO_CODE_MESSAGES: Readonly> = {
- terminate:
- 'Terminate names nothing: it stops every running path in this scope; ' +
- 'leave the payload out.',
- cancel:
- 'Cancel names nothing: it gives up the block this end sits in; leave the ' +
- 'payload out.',
+ terminate: diagnosticText(
+ "'terminate' takes no payload",
+ 'note: it stops every running path in this scope and names nothing',
+ 'help: remove the payload',
+ ),
+ cancel: diagnosticText(
+ "'cancel' takes no payload",
+ 'note: it gives up the block this end sits in and names nothing',
+ 'help: remove the payload',
+ ),
} satisfies Record<(typeof END_TRIGGERS)[number], string>;
-export const CANCEL_END_PLACEMENT_MESSAGE =
- "A cancel end belongs directly inside an 'attempt' block: it gives that " +
- 'block up, and the engine refuses one anywhere else. Wrap the steps to ' +
- `give up in 'attempt { ... }', or end this path with a plain 'end'.`;
+export const CANCEL_END_PLACEMENT_MESSAGE = diagnosticText(
+ "this cancel end is not inside an 'attempt' block",
+ 'note: a cancel end gives up the block it sits in, and the engine refuses one anywhere else',
+ "help: wrap the steps to give up in 'attempt { ... }', or end this path with a plain 'end'",
+);
-export const CANCEL_HOSTLESS_MESSAGE =
- "A cancel is caught on the block it gives up; write 'on : cancel'. " +
- 'A handler with no host opens on its own trigger, and nothing opens on a ' +
- 'cancel.';
+export const CANCEL_HOSTLESS_MESSAGE = diagnosticText(
+ 'this cancel handler names no block',
+ 'note: a cancel is caught on the block it gives up',
+ 'note: a handler with no host opens on its own trigger, and nothing opens on a cancel',
+ "help: write 'on : cancel'",
+);
-export const CANCEL_ALONGSIDE_MESSAGE =
- 'Giving a block up ends every step still running inside it, so there is ' +
- "nothing left to run alongside; remove 'alongside'.";
+export const CANCEL_ALONGSIDE_MESSAGE = diagnosticText(
+ "a cancel handler cannot run 'alongside'",
+ 'note: giving a block up ends every step still running inside it, so nothing is left to run alongside',
+ "help: remove 'alongside'",
+);
-export const EMPTY_CODE_MESSAGE =
- 'An empty code ("") is not a catch-all; to catch every error, leave the ' +
- 'payload out entirely.';
+export const EMPTY_CODE_MESSAGE = diagnosticText(
+ 'an empty code ("") is not a catch-all',
+ 'help: to catch every error, leave the payload out',
+);
-export const CANCEL_NO_CODE_MESSAGE =
- 'A cancel handler catches nothing by name: it runs when its block is ' +
- 'given up; leave the payload out.';
+export const CANCEL_NO_CODE_MESSAGE = diagnosticText(
+ 'a cancel handler catches nothing by name',
+ 'note: it runs when its block is given up',
+ 'help: leave the payload out',
+);
-export const CANCEL_NOT_RAISED_MESSAGE =
- 'A cancel is not raised: it is how a block gives itself up; write ' +
- `'end cancel' inside the 'attempt' block.`;
+const CANCEL_IS_GIVING_UP_NOTE =
+ 'note: a cancel is how a block gives itself up';
-export const CANCEL_NOT_AWAITED_MESSAGE =
- 'A cancel is not awaited: it is how a block gives itself up; write ' +
- `'end cancel' inside the 'attempt' block, and ` +
- `'on : cancel' beside the block to say what happens then.`;
+const CANCEL_END_HELP =
+ "help: write 'end cancel' inside the 'attempt' block";
-export const COMPENSATION_NO_CODE_MESSAGE =
- "Compensation has no code or name: 'on compensation { }' is the undo block " +
- 'of the subprocess or attempt block it sits in; leave the payload out.';
+export const CANCEL_NOT_RAISED_MESSAGE = diagnosticText(
+ 'a cancel cannot be raised',
+ CANCEL_IS_GIVING_UP_NOTE,
+ CANCEL_END_HELP,
+);
-export const COMPENSATION_BINDINGS_MESSAGE =
- "'(code: c)' bindings belong to error and escalation handlers; compensation carries no values.";
+export const CANCEL_NOT_AWAITED_MESSAGE = diagnosticText(
+ 'a cancel cannot be awaited',
+ CANCEL_IS_GIVING_UP_NOTE,
+ CANCEL_END_HELP,
+ "help: write 'on : cancel' beside the block to say what happens then",
+);
-export const COMPENSATION_ALONGSIDE_MESSAGE =
- 'The work an undo block reverses has already finished, so there is no ' +
- "running flow to run alongside; remove 'alongside'.";
+export const COMPENSATION_NO_CODE_MESSAGE = diagnosticText(
+ 'compensation takes no code or name',
+ "note: 'on compensation { }' is the undo block of the subprocess or attempt block it sits in",
+ 'help: leave the payload out',
+);
-export const COMPENSATION_PLACEMENT_MESSAGE =
- "An undo block belongs directly inside the 'subprocess' or 'attempt' whose " +
- 'work it undoes: a process cannot undo itself.';
+export const COMPENSATION_BINDINGS_MESSAGE = diagnosticText(
+ 'compensation carries no values to bind',
+ "note: '(code: c)' bindings belong to error and escalation handlers",
+);
-export const COMPENSATION_DUPLICATE_MESSAGE =
- 'A subprocess or an attempt block has one undo block; merge the steps.';
+export const COMPENSATION_ALONGSIDE_MESSAGE = diagnosticText(
+ "an undo block cannot run 'alongside'",
+ 'note: the work it reverses has already finished, so no flow is running alongside',
+ "help: remove 'alongside'",
+);
-export const COMPENSATION_HOST_MESSAGE =
- "Compensation cannot attach to a host: it undoes a subprocess's " +
- 'already-completed work through its own undo block, not through a ' +
- "boundary event; remove the host and write 'on compensation { ... }' " +
- 'directly inside the subprocess or attempt block it reverses.';
+export const COMPENSATION_PLACEMENT_MESSAGE = diagnosticText(
+ "this undo block is not directly inside a 'subprocess' or 'attempt'",
+ "note: an undo block belongs directly inside the 'subprocess' or 'attempt' whose work it undoes",
+ 'note: a process cannot undo itself',
+);
+
+export const COMPENSATION_DUPLICATE_MESSAGE = diagnosticText(
+ 'this subprocess or attempt block already has an undo block',
+ 'help: merge the steps into one undo block',
+);
-export const LINK_CATCH_FLOW_MESSAGE =
- "Nothing may flow into an 'await link': end the path before it with 'end', " +
- "'throw', 'goto', or 'emit link', because a link catch is entered only by " +
- "'emit link' of the same name.";
+export const COMPENSATION_HOST_MESSAGE = diagnosticText(
+ 'compensation cannot attach to a host',
+ "note: it undoes a subprocess's completed work through its own undo block, not through a boundary event",
+ "help: remove the host and write 'on compensation { ... }' directly inside the subprocess or attempt block it reverses",
+);
-export const LINK_IN_RACE_MESSAGE =
- "'link' cannot head a branch of an 'await' block: the engine refuses a link " +
- `catch after an event-based gateway; write 'await link("")' as its ` +
- 'own statement.';
+export const LINK_CATCH_FLOW_MESSAGE = diagnosticText(
+ "the flow runs into an 'await link'",
+ "note: a link catch is entered only by 'emit link' of the same name",
+ "help: end the path before it with 'end', 'throw', 'goto', or 'emit link'",
+);
+
+export const LINK_IN_RACE_MESSAGE = diagnosticText(
+ "'link' cannot head a branch of an 'await' block",
+ 'note: the engine refuses a link catch after an event-based gateway',
+ `help: write 'await link("")' as its own statement`,
+);
export const ESCALATION_NO_MESSAGE_MESSAGE =
- 'An escalation carries a code but no message.';
+ 'an escalation carries a code but no message';
-export const DECLARATION_SETTINGS_ONLY_MESSAGE =
- `A declaration's parens take only ${formatWordList(EVENT_BINDING_FIELDS)} ` +
- "settings, written 'key: value'.";
+export const DECLARATION_SETTINGS_ONLY_MESSAGE = diagnosticText(
+ "this value in a declaration's parens is not a setting",
+ `note: a declaration's parens take only ${formatWordList(EVENT_BINDING_FIELDS)} settings, written 'key: value'`,
+);
export const settingsOnlyMessage = (description: string) =>
- `The parens of ${description} take only settings, written 'key: value'.`;
+ diagnosticText(
+ `this value in the parens of ${description} is not a setting`,
+ `note: the parens of ${description} take only settings, written 'key: value'`,
+ );
export const loopJoinKeyMessage = (key: string, description: string) =>
- `Setting '${key}' is not valid on ${description}: a loop has one gateway, so write '${ENGINE_KEY_BY_JOIN_KEY[key]}'.`;
+ diagnosticText(
+ `setting '${key}' is not valid on ${description}`,
+ 'note: a loop has one gateway',
+ `help: write '${ENGINE_KEY_BY_JOIN_KEY[key]}'`,
+ );
export const refusedHeadKeyMessage = (
key: string,
description: string,
): string =>
- `Setting '${key}' is not valid on ${description}: Operaton refuses it ` +
- 'on an event-based gateway (BpmnParse.parseEventBasedGateway). Write it on ' +
- 'the branch triggers instead.';
+ diagnosticText(
+ `setting '${key}' is not valid on ${description}`,
+ 'note: Operaton refuses it on an event-based gateway',
+ 'help: write it on the branch triggers',
+ );
export const prunedJoinMessage = (description: string, key: string) =>
- `Every branch of this ${description.replace(/^an? /, '')} ends its path, so there is no join for '${key}' to set; the setting has no effect.`;
+ diagnosticText(
+ `setting '${key}' has no effect`,
+ `note: every branch of this ${description.replace(/^an? /, '')} ends its path, so there is no join for it to set`,
+ );
export const noJobMessage = (
key: string,
pairing: readonly string[],
description: string,
): string =>
- `Setting '${key}' on ${description} configures no job: Operaton creates ` +
- `one only when ${formatWordList(pairing)} is also set ` +
- '(BpmnParse.parseAsynchronousContinuation, DefaultFailedJobParseListener.parseActivity).';
+ diagnosticText(
+ `setting '${key}' on ${description} configures no job`,
+ `note: Operaton creates one only when ${formatWordList(pairing)} is also set`,
+ );
export const noPerRunJobMessage = (
key: string,
pairing: readonly string[],
description: string,
): string =>
- `Setting '${key}' on ${description} prices the per-run job Operaton ` +
- 'creates in the multi-instance body (BpmnParse.parseActivity), which ' +
- `exists only when ${formatWordList(pairing)} is also set.`;
+ diagnosticText(
+ `setting '${key}' on ${description} configures no per-run job`,
+ `note: Operaton creates the per-run job in the multi-instance body only when ${formatWordList(pairing)} is also set`,
+ );
/**
* A timer creates its own job regardless of the async flags: a node with its
@@ -1312,21 +1644,37 @@ const BOOLEAN_OK: ReadonlySet = new Set([
'unknown',
]);
-function collectNamedStatements(process: Process): NamedStatement[] {
- return AstUtils.streamAst(process).filter(isNamedStatement).toArray();
+function statementName(stmt: Statement): string | undefined {
+ return isNamedStatement(stmt) ? stmt.name : undefined;
}
-function collectGotoTargetNames(process: Process): Set {
- return new Set(
- AstUtils.streamAst(process)
- .filter(isGotoStatement)
- .map((goto) => goto.target?.$refText ?? '')
- .filter((name) => name.length > 0),
- );
+/**
+ * Names a `goto` can enter `stmt` by. A loop's back-edge leads every step of
+ * its body to the loop's gateway, so a `goto` to any of them enters the whole
+ * loop.
+ */
+function entryNames(stmt: Statement): string[] {
+ return [
+ ...ownName(stmt),
+ ...(isWhileStatement(stmt) || isDoWhileStatement(stmt)
+ ? flowNames(stmt.body)
+ : []),
+ ];
}
-function statementName(stmt: Statement): string | undefined {
- return isNamedStatement(stmt) ? stmt.name : undefined;
+/** Every step a block's own flow runs through, nested blocks included. */
+function flowNames(block: Block | undefined): string[] {
+ return blockStatements(block)
+ .filter((stmt) => !isOnHandler(stmt))
+ .flatMap((stmt) => [
+ ...ownName(stmt),
+ ...childBlocks(stmt).flatMap(flowNames),
+ ]);
+}
+
+function ownName(stmt: Statement): string[] {
+ const name = statementName(stmt);
+ return name === undefined ? [] : [name];
}
/**
@@ -1408,31 +1756,37 @@ function statementTerminates(stmt: Statement): boolean {
}
// With every parallel branch conditioned, the transform's fallback runs straight to the join.
const counts = isIfStatement(stmt)
- ? stmt.elseBlock !== undefined
+ ? stmt.elseBlock !== undefined || stmt.fail !== undefined
: isDoWhileStatement(stmt) ||
isRaceStatement(stmt) ||
(isParallelStatement(stmt) &&
- stmt.branches.some((branch) => branch.condition === undefined));
+ (stmt.fail !== undefined ||
+ stmt.branches.some((branch) => branch.condition === undefined)));
return (
counts &&
childBlocks(stmt).every((block) => blockTerminates(blockStatements(block)))
);
}
-function hasConditionedBranch(stmt: ParallelStatement): boolean {
- return stmt.branches.some((branch) => branch.condition !== undefined);
-}
-
-function hasUnconditionedBranch(stmt: ParallelStatement): boolean {
- return stmt.branches.some(
- (branch) => branch.condition === undefined && !branch.otherwise,
- );
+function checkElseFailWord(
+ stmt: IfStatement | ParallelStatement,
+ accept: ValidationAcceptor,
+): void {
+ if (stmt.fail === undefined || stmt.fail === ELSE_FAIL_WORD) return;
+ accept('error', elseFailWordMessage(stmt.fail), {
+ node: stmt,
+ property: 'fail',
+ });
}
+/**
+ * The transform takes a block's exit from its last flow statement, so a
+ * terminator followed by a re-entry (a link catch, a `goto` target) leaves the
+ * block open.
+ */
function blockTerminates(statements: Statement[]): boolean {
- return statements.some(
- (stmt) => !isOnHandler(stmt) && statementTerminates(stmt),
- );
+ const last = statements.findLast((stmt) => !isOnHandler(stmt));
+ return last !== undefined && statementTerminates(last);
}
function previousFlowStatement(
@@ -1512,8 +1866,10 @@ export class BpmnScriptValidator {
(extra) =>
accept(
'error',
- 'Only one process is supported per file. ' +
- 'Move additional processes into separate files.',
+ diagnosticText(
+ 'only one process is supported per file',
+ 'help: move additional processes into separate files',
+ ),
{ node: extra, property: 'name' },
),
);
@@ -1526,9 +1882,10 @@ export class BpmnScriptValidator {
*/
private checkStartPosition(
process: Process,
+ nodes: readonly AstNode[],
accept: ValidationAcceptor,
): void {
- for (const node of AstUtils.streamAst(process)) {
+ for (const node of nodes) {
if (!isStartEvent(node) || node.name === undefined) continue;
if (node.$container === process) {
const prev = previousFlowStatement(
@@ -1544,10 +1901,11 @@ export class BpmnScriptValidator {
}
accept(
'error',
- `'start ${node.name}' opens an entry of its own and takes no incoming flow, ` +
- 'but the statement before it still flows on to it. Close that flow ' +
- "first (with 'end', 'throw', or 'goto') or move the start ahead of " +
- 'that step.',
+ diagnosticText(
+ `the statement before 'start ${node.name}' still flows on to it`,
+ 'note: a start opens an entry of its own and takes no incoming flow',
+ "help: close that flow first with 'end', 'throw', or 'goto', or move the start ahead of that step",
+ ),
{ node, property: 'name' },
);
continue;
@@ -1566,8 +1924,11 @@ export class BpmnScriptValidator {
}
accept(
'error',
- `'start ${node.name}' must be a top-level statement of its process, or the first statement of its subprocess, attempt block, or event-handler body. ` +
- 'A start event cannot have incoming flows.',
+ diagnosticText(
+ `'start ${node.name}' is neither a top-level statement nor the first statement of its block`,
+ 'note: a start event cannot have incoming flows',
+ 'note: a start belongs at the top level of its process, or first in its subprocess, attempt block, or event-handler body',
+ ),
{ node, property: 'name' },
);
}
@@ -1647,31 +2008,36 @@ export class BpmnScriptValidator {
if (process.name !== undefined && hasNoFlowStep(process.body)) {
accept(
'error',
- `Process '${process.name}' has no flow steps: a process needs at least one step on its main flow (handlers alone do not start a process).`,
+ diagnosticText(
+ `process '${process.name}' has no flow steps`,
+ 'note: a process needs at least one step on its main flow, and handlers alone do not start it',
+ ),
{ node: process, property: 'name' },
);
}
const symbols = this.variables.collect(process);
+ const nodes = AstUtils.streamAst(process).toArray();
this.checkKeywordVarDecls(process, accept);
- for (const expr of collectExpressions(process)) {
+ for (const expr of nodes.filter(isExpr)) {
this.checkExpression(expr, symbols, accept);
}
- this.checkStartPosition(process, accept);
+ this.checkStartPosition(process, nodes, accept);
this.checkDefaultStart(process, accept);
- const named = collectNamedStatements(process);
+ const named = nodes.filter(isNamedStatement);
this.checkReservedNames(named, accept);
+ checkEngineIds([process, ...named], accept);
this.checkDuplicateVarDecls(process, accept);
this.checkProcessAttributes(process, accept);
this.checkDuplicateStatementNames(process, named, accept);
- this.checkFormVariableAgreement(process, accept);
- this.checkUnreachableStatements(process, accept);
- this.checkLinkEvents(process, accept);
- this.checkHandlerDuplicates(process, accept);
+ this.checkFormVariableAgreement(process, nodes, accept);
+ this.checkUnreachableStatements(process, nodes, accept);
+ this.checkLinkEvents(nodes, accept);
+ this.checkHandlerDuplicates(nodes, accept);
this.checkCodeDecls(process, accept);
};
@@ -1683,9 +2049,15 @@ export class BpmnScriptValidator {
*/
private checkUnreachableStatements(
process: Process,
+ nodes: readonly AstNode[],
accept: ValidationAcceptor,
): void {
- const gotoTargets = collectGotoTargetNames(process);
+ const gotoTargets = new Set(
+ nodes
+ .filter(isGotoStatement)
+ .map((goto) => goto.target?.$refText ?? '')
+ .filter((name) => name.length > 0),
+ );
const scan = (statements: Statement[]): void => {
let reachable = true;
@@ -1702,24 +2074,15 @@ export class BpmnScriptValidator {
property: 'trigger',
});
}
- const name = statementName(stmt);
if (
isStartEvent(stmt) ||
isLinkCatch(stmt) ||
- (name !== undefined && gotoTargets.has(name))
+ entryNames(stmt).some((name) => gotoTargets.has(name))
) {
reachable = true;
}
if (!reachable) {
- accept(
- 'error',
- 'This step can never run: an earlier `end`, `throw`, `goto`, ' +
- '`emit link`, or an all-terminating `if`/`parallel`/`await` in ' +
- 'the same block always ends or redirects the flow before ' +
- 'reaching it, so this step would lower to a disconnected node ' +
- 'with no incoming flow, which is invalid BPMN.',
- { node: stmt },
- );
+ accept('error', UNREACHABLE_MESSAGE, { node: stmt });
} else {
for (const block of childBlocks(stmt)) {
scan(blockStatements(block));
@@ -1740,10 +2103,13 @@ export class BpmnScriptValidator {
* (`ScopeImpl.findActivityAtLevelOfSubprocess`); a catch with no throw
* deploys, so it only warns.
*/
- private checkLinkEvents(process: Process, accept: ValidationAcceptor): void {
+ private checkLinkEvents(
+ nodes: readonly AstNode[],
+ accept: ValidationAcceptor,
+ ): void {
const throws: EmitStatement[] = [];
const catches: IntermediateCatchEvent[] = [];
- for (const node of AstUtils.streamAst(process)) {
+ for (const node of nodes) {
if (isLinkThrow(node) && payloadTextOf(node.items)) throws.push(node);
if (isLinkCatch(node) && payloadTextOf(node.items)) catches.push(node);
}
@@ -1757,9 +2123,10 @@ export class BpmnScriptValidator {
forEachDuplicate(catches, nameOf, (extra) =>
accept(
'error',
- `Another 'await link("${nameOf(extra)}")' already catches this link: ` +
- 'the engine keeps one catch per link name in the whole file, even ' +
- 'across subprocesses.',
+ diagnosticText(
+ `another 'await link("${nameOf(extra)}")' already catches this link`,
+ 'note: the engine keeps one catch per link name in the whole file, even across subprocesses',
+ ),
at(extra),
),
);
@@ -1773,9 +2140,11 @@ export class BpmnScriptValidator {
if (catchEvent === undefined) {
accept(
'error',
- `No 'await link("${name}")' catches this link, and the engine ` +
- 'refuses to deploy an emitted link with no catch of its name. ' +
- 'Write one where the flow should continue.',
+ diagnosticText(
+ `no 'await link("${name}")' catches this link`,
+ 'note: the engine refuses to deploy an emitted link with no catch of its name',
+ 'help: write one where the flow should continue',
+ ),
at(throwEvent),
);
continue;
@@ -1783,9 +2152,11 @@ export class BpmnScriptValidator {
if (enclosingFlowContainer(catchEvent) !== container) {
accept(
'error',
- `'emit link("${name}")' must sit in the same process, subprocess, ` +
- "or handler body as its 'await link': a link cannot cross a " +
- "subprocess or handler boundary, the same way a 'goto' cannot.",
+ diagnosticText(
+ `'emit link("${name}")' and its 'await link' sit in different scopes`,
+ "note: a link cannot cross a subprocess or handler boundary, the same way a 'goto' cannot",
+ 'help: put both in the same process, subprocess, or handler body',
+ ),
at(throwEvent),
);
continue;
@@ -1812,8 +2183,10 @@ export class BpmnScriptValidator {
if (thrown.has(nameOf(catchEvent))) continue;
accept(
'warning',
- `No 'emit link("${nameOf(catchEvent)}")' names this catch, so it ` +
- 'and the steps after it never run.',
+ diagnosticText(
+ `no 'emit link("${nameOf(catchEvent)}")' names this catch`,
+ 'note: the catch and the steps after it never run',
+ ),
at(catchEvent),
);
}
@@ -1822,6 +2195,7 @@ export class BpmnScriptValidator {
/** Each binds the same process variable; a catch binding always fills a `string`. */
private checkFormVariableAgreement(
process: Process,
+ nodes: readonly AstNode[],
accept: ValidationAcceptor,
): void {
const declaredType = new Map();
@@ -1841,7 +2215,7 @@ export class BpmnScriptValidator {
declaredType.set(decl.name, decl.type);
}
}
- for (const node of AstUtils.streamAst(process)) {
+ for (const node of nodes) {
if (isOnHandler(node)) {
for (const binding of caughtBindingsOf(node.items)) {
if (binding.variable === undefined) continue;
@@ -1849,7 +2223,7 @@ export class BpmnScriptValidator {
if (prior === undefined) continue;
accept(
'error',
- `Catch-binding variable '${binding.variable}' is typed 'string', but '${binding.variable}' is already declared as '${prior}'; the types must agree.`,
+ `catch-binding variable '${binding.variable}' is typed 'string', but '${binding.variable}' is already declared as '${prior}'`,
{ node: binding.node, property: 'value' },
);
}
@@ -1865,7 +2239,7 @@ export class BpmnScriptValidator {
if (prior === undefined) continue;
accept(
'error',
- `Form field '${field.id}' is typed '${field.type}', but '${field.id}' is already declared as '${prior}'; the types must agree.`,
+ `form field '${field.id}' is typed '${field.type}', but '${field.id}' is already declared as '${prior}'`,
{ node: field, property: 'type' },
);
}
@@ -1886,16 +2260,19 @@ export class BpmnScriptValidator {
if (role !== undefined) {
accept(
'error',
- `Statement name '${node.name}' is the id the compiler generates for ` +
- `the implicit ${role} event of '${container}'; choose another name.`,
+ diagnosticText(
+ `statement name '${node.name}' is the id generated for the implicit ${role} event of '${container}'`,
+ 'help: choose another name',
+ ),
{ node, property: 'name' },
);
} else if (isReservedName(node.name)) {
accept(
'error',
- `Statement name '${node.name}' matches a reserved synthesized-id pattern. ` +
- `Prefixes ${RESERVED_ID_SHAPE_LIST} are reserved for ids the ` +
- 'desugarer or the layouter generates.',
+ diagnosticText(
+ `statement name '${node.name}' matches a reserved id pattern`,
+ `note: the shapes ${RESERVED_ID_SHAPE_LIST} are reserved for ids the compiler generates`,
+ ),
{ node, property: 'name' },
);
}
@@ -1915,7 +2292,7 @@ export class BpmnScriptValidator {
(decl) =>
accept(
'error',
- `Variable '${decl.name}' is already declared in process '${process.name}'.`,
+ `variable '${decl.name}' is already declared in process '${process.name}'`,
{ node: decl, property: 'name' },
),
);
@@ -1958,8 +2335,10 @@ export class BpmnScriptValidator {
(node) =>
accept(
'error',
- `Step name '${node.name}' is already used by another step in process ` +
- `'${process.name}'; 'goto ${node.name}' would be ambiguous.`,
+ diagnosticText(
+ `step name '${node.name}' is already used by another step in process '${process.name}'`,
+ `note: 'goto ${printName(node.name)}' would be ambiguous`,
+ ),
{ node, property: 'name' },
),
);
@@ -1969,8 +2348,10 @@ export class BpmnScriptValidator {
if (node.name !== process.name) continue;
accept(
'error',
- `Step name '${node.name}' equals the process id; the compiled ` +
- 'document can hold only one element with that id.',
+ diagnosticText(
+ `step name '${node.name}' equals the process id`,
+ 'note: the compiled document can hold only one element with that id',
+ ),
{ node, property: 'name' },
);
}
@@ -2006,7 +2387,17 @@ export class BpmnScriptValidator {
}
const container = expr.$container;
- if (isVarRef(expr)) {
+ if (isVarRef(expr) && isQuotedOutsideCode(expr)) {
+ accept(
+ 'error',
+ diagnosticText(
+ `'${expr.ref.$refText}' in backticks is not a variable`,
+ 'note: backticks spell the name of a step, a process or a code',
+ `help: to refer to a variable named '${expr.ref.$refText}', write the quoted raw expression "\${${expr.ref.$refText}}"`,
+ ),
+ { node: expr, property: 'ref' },
+ );
+ } else if (isVarRef(expr)) {
const nameTrigger = nameTriggerOf(expr);
const variableUse = isVariableUse(expr);
if (nameTrigger !== undefined) {
@@ -2029,7 +2420,10 @@ export class BpmnScriptValidator {
if (variableUse && !symbols.has(expr.ref.$refText)) {
accept(
'warning',
- `Variable '${expr.ref.$refText}' is not declared. Add 'var ${expr.ref.$refText}: ' to the process.`,
+ diagnosticText(
+ `variable '${expr.ref.$refText}' is not declared`,
+ `help: add 'var ${expr.ref.$refText}: ' to the process`,
+ ),
{ node: expr, property: 'ref' },
);
}
@@ -2038,6 +2432,12 @@ export class BpmnScriptValidator {
if (isRawExpr(expr)) {
checkRawTemplateNames(expr.raw, { node: expr, property: 'raw' }, accept);
+ if (nestsTemplate(expr.raw)) {
+ accept('error', NESTED_TEMPLATE_MESSAGE, {
+ node: expr,
+ property: 'raw',
+ });
+ }
// A raw's body is spliced into the surrounding expression; the top is rendered as written.
if (
(isExpr(container) || isAccessor(container)) &&
@@ -2117,7 +2517,7 @@ export class BpmnScriptValidator {
if (!allowed.has(type)) {
accept(
'error',
- `Variable '${operand.ref.$refText}' of type '${type}' cannot be used in ${context} (operator '${node.op}').`,
+ `variable '${operand.ref.$refText}' of type '${type}' cannot be used in ${context} with '${node.op}'`,
{ node, property: side },
);
}
@@ -2201,7 +2601,7 @@ export class BpmnScriptValidator {
if (rule.code === 'required' && !name) {
accept(
'error',
- nameRequiredMessage(`A ${start.trigger} start`, start.trigger!),
+ nameRequiredMessage(`a ${start.trigger} start`, start.trigger!),
{ node: start, property: 'trigger' },
);
}
@@ -2219,13 +2619,7 @@ export class BpmnScriptValidator {
}
this.checkConditionPayload(start, rule, 'start', accept);
-
- this.checkTimerClause(
- start,
- rule.timer,
- particleOnlyMessage('a timer start'),
- accept,
- );
+ this.checkTimerClause(start, rule.timer, 'start', accept);
}
checkEndEvent = (end: EndEvent, accept: ValidationAcceptor): void => {
@@ -2262,13 +2656,6 @@ export class BpmnScriptValidator {
}
};
- checkAttributeOwner = (
- owner: AttributeOwner,
- accept: ValidationAcceptor,
- ): void => {
- this.checkAttributeBlock(owner, accept);
- };
-
checkUserTask = (task: UserTask, accept: ValidationAcceptor): void => {
this.checkAttributeBlock(task, accept);
this.checkFormReference(task, accept);
@@ -2293,8 +2680,7 @@ export class BpmnScriptValidator {
accept('error', FORM_REF_BINDING_MESSAGE, target);
return;
}
- this.checkBindingAttribute(task, accept);
- this.checkBindingVersionExclusion(task, 'A user task', accept);
+ this.checkVersionPin(task, 'a user task', accept);
}
/** The engine runs a send task as a service task. */
@@ -2306,7 +2692,7 @@ export class BpmnScriptValidator {
if (task.name === undefined) return;
this.checkImplementationBinding(
task,
- `${isServiceTask(task) ? 'Service' : 'Send'} task '${task.name}'`,
+ `${isServiceTask(task) ? 'service' : 'send'} task '${task.name}'`,
SERVICE_TASK_BINDING_KEYS,
accept,
);
@@ -2321,14 +2707,13 @@ export class BpmnScriptValidator {
if (task.name !== undefined) {
this.checkImplementationBinding(
task,
- `Decision step '${task.name}'`,
+ `decision step '${task.name}'`,
BUSINESS_RULE_BINDING_KEYS,
accept,
);
}
this.checkDecisionModifiers(task, accept);
- this.checkBindingAttribute(task, accept);
- this.checkBindingVersionExclusion(task, 'A decision step', accept);
+ this.checkVersionPin(task, 'a decision step', accept);
this.checkDecisionResultMapping(task, accept);
};
@@ -2465,7 +2850,7 @@ export class BpmnScriptValidator {
if (value === undefined || !DECISION_RESULT_MAPPING_SET.has(value)) {
accept(
'error',
- `Setting 'mapDecisionResult' must be ${formatWordList(DECISION_RESULT_MAPPINGS)}.`,
+ `setting 'mapDecisionResult' must be ${formatWordList(DECISION_RESULT_MAPPINGS)}`,
{ node: attr, property: 'value' },
);
return;
@@ -2489,8 +2874,10 @@ export class BpmnScriptValidator {
// An unterminated fence recovers into a bodyless ScriptTask with no CST node for the body.
accept(
'error',
- `Script task '${task.name}' has a malformed or unterminated fenced ` +
- 'script body; a script must be a closed ``` ... ``` block.',
+ diagnosticText(
+ `script task '${task.name}' has a malformed or unterminated fenced script body`,
+ 'note: a script is a closed ``` ... ``` block',
+ ),
{ node: task, property: 'name' },
);
return;
@@ -2498,7 +2885,7 @@ export class BpmnScriptValidator {
checkFencedScript(
task.body,
- `Script task '${task.name}'`,
+ `script task '${task.name}'`,
{ node: task, property: 'body' },
accept,
);
@@ -2512,7 +2899,10 @@ export class BpmnScriptValidator {
forms.slice(1).forEach((form) => {
accept(
'error',
- `${ownerDescription} may declare at most one 'form' block.`,
+ diagnosticText(
+ `${ownerDescription} has a second 'form' block`,
+ "note: it may declare one 'form' block at most",
+ ),
{ node: form },
);
});
@@ -2522,7 +2912,7 @@ export class BpmnScriptValidator {
form.fields,
(field) => field.id,
(field) =>
- accept('error', `Duplicate form field '${field.id}'.`, {
+ accept('error', `duplicate form field '${field.id}'`, {
node: field,
property: 'id',
}),
@@ -2531,7 +2921,10 @@ export class BpmnScriptValidator {
if (field.type !== undefined && !FORM_FIELD_TYPE_SET.has(field.type)) {
accept(
'error',
- `Form field '${field.id}' has type '${field.type}', which a form cannot use. Use ${formatPlainWordList(FORM_FIELD_TYPES)}.`,
+ diagnosticText(
+ `form field '${field.id}' has type '${field.type}', which a form cannot use`,
+ `help: use ${formatPlainWordList(FORM_FIELD_TYPES)}`,
+ ),
{ node: field, property: 'type' },
);
}
@@ -2667,7 +3060,10 @@ export class BpmnScriptValidator {
for (const form of forms) {
accept(
'error',
- `${description} cannot declare a 'form' block; forms belong on start events and user tasks.`,
+ diagnosticText(
+ `${description} cannot declare a 'form' block`,
+ 'note: forms belong on start events and user tasks',
+ ),
{ node: form },
);
}
@@ -2680,7 +3076,15 @@ export class BpmnScriptValidator {
description: string,
accept: ValidationAcceptor,
): void {
- this.checkAllowedKeys(attrs, allowed, description, accept);
+ for (const attr of attrs) {
+ if (!allowed.has(attr.key)) {
+ accept(
+ 'error',
+ `setting '${attr.key}' is not valid on ${description}`,
+ { node: attr, property: 'key' },
+ );
+ }
+ }
this.checkAttributeValues(attrs, allowed, accept);
}
@@ -2697,7 +3101,7 @@ export class BpmnScriptValidator {
if (written.length === 0) {
accept(
'error',
- `${subject} must declare a ${formatWordList(keys)} setting${alternative}.`,
+ `${subject} has no ${formatWordList(keys)} setting${alternative}`,
target,
);
return false;
@@ -2714,7 +3118,7 @@ export class BpmnScriptValidator {
attrs,
(attr) => attr.key,
(attr) =>
- accept('error', `Duplicate setting '${attr.key}'.`, {
+ accept('error', `duplicate setting '${attr.key}'`, {
node: attr,
property: 'key',
}),
@@ -2733,33 +3137,13 @@ export class BpmnScriptValidator {
): void {
for (const flag of flagsOf(items)) {
if (legal.includes(flag.flag)) continue;
- accept('error', `Flag '${flag.flag}' is not valid on ${description}.`, {
+ accept('error', `flag '${flag.flag}' is not valid on ${description}`, {
node: flag,
property: 'flag',
});
}
}
- private checkAllowedKeys(
- attrs: readonly Setting[],
- allowed: ReadonlySet,
- description: string,
- accept: ValidationAcceptor,
- ): void {
- for (const attr of attrs) {
- if (!allowed.has(attr.key)) {
- accept(
- 'error',
- `Setting '${attr.key}' is not valid on ${description}.`,
- {
- node: attr,
- property: 'key',
- },
- );
- }
- }
- }
-
/**
* A boolean flag or engine text field takes one shape and drops the rest
* silently: `asyncBefore: "true"` emits no attribute at all.
@@ -2785,8 +3169,10 @@ export class BpmnScriptValidator {
) {
accept(
'error',
- `Setting '${attr.key}' takes a quoted string or a "\${...}" ` +
- 'expression; put the value in quotes.',
+ diagnosticText(
+ `setting '${attr.key}' is not a quoted string or a "\${...}" expression`,
+ 'help: put the value in quotes',
+ ),
{ node: attr, property: 'value' },
);
} else if (
@@ -2823,16 +3209,16 @@ export class BpmnScriptValidator {
} else {
const binding = bindingValueMessage(attr.key, attr.value);
if (binding !== undefined) {
- accept('error', binding, { node: attr, property: 'value' });
+ accept(binding[0], binding[1], { node: attr, property: 'value' });
}
}
}
}
- private checkAttributeBlock(
+ checkAttributeBlock = (
owner: AttributeOwner,
accept: ValidationAcceptor,
- ): void {
+ ): void => {
const rule = attributeBlockRuleOf(owner)!;
this.checkDuplicateKeys(settingsOf(owner.items), accept);
const settings = configuredSettingsOf(owner);
@@ -2845,20 +3231,71 @@ export class BpmnScriptValidator {
accept,
);
this.checkRunSettings(owner, rule, settings, accept);
+ this.checkRepeatDocumentation(owner, settings, accept);
this.checkJobSettingPairing(owner, rule, settings, accept);
this.checkFlags(owner.items, rule.flags, rule.description, accept);
if ('forms' in owner) {
if (rule.forms) {
this.checkFormBlocks(owner.forms, rule.description, accept);
} else {
- this.rejectFormBlock(owner.forms, capitalize(rule.description), accept);
+ this.rejectFormBlock(owner.forms, rule.description, accept);
}
}
this.checkIoParameters(owner, rule, accept);
this.checkExternalExtras(owner, rule, accept);
this.checkListeners(owner, rule, accept);
+ };
+
+ private checkRepeatDocumentation(
+ owner: AttributeOwner,
+ settings: readonly Setting[],
+ accept: ValidationAcceptor,
+ ): void {
+ const clause = owner as { cardinality?: Expr; element?: string };
+ for (const setting of settings) {
+ const message =
+ setting.key === VALUE_DOCUMENTATION_KEYS.count &&
+ clause.cardinality === undefined
+ ? COUNT_DOCUMENTATION_MESSAGE
+ : setting.key === VALUE_DOCUMENTATION_KEYS.each &&
+ clause.element === undefined
+ ? EACH_DOCUMENTATION_MESSAGE
+ : undefined;
+ if (message !== undefined) {
+ accept('error', message, { node: setting, property: 'key' });
+ }
+ }
}
+ /** The parentheses around a condition hold the condition's documentation alone. */
+ checkConditionItem = (item: ParenItem, accept: ValidationAcceptor): void => {
+ const property = item.$containerProperty;
+ if (property !== 'conditionItems' && property !== 'completionItems') {
+ return;
+ }
+ const key = VALUE_DOCUMENTATION_KEYS.condition;
+ if (!isSetting(item) || item.key !== key) {
+ const message =
+ isSetting(item) && item.key === DOCUMENTATION_KEY
+ ? CONDITION_DOCUMENTATION_KEY_MESSAGE
+ : CONDITION_ITEM_MESSAGE;
+ accept('error', message, { node: item });
+ return;
+ }
+ const siblings = (
+ item.$container as unknown as Record
+ )[property]!;
+ const first = siblings.find(
+ (sibling) => isSetting(sibling) && sibling.key === key,
+ );
+ if (first !== item) {
+ accept('error', `duplicate setting '${key}'`, {
+ node: item,
+ property: 'key',
+ });
+ }
+ };
+
private checkRunSettings(
owner: AttributeOwner,
rule: AttributeBlockRule,
@@ -2967,7 +3404,7 @@ export class BpmnScriptValidator {
const refusal = namesFieldBinding(settings)
? undefined
: fieldBindingMessage(
- capitalize(rule.description),
+ rule.description,
fieldlessBindingsOf(settings),
ELEMENT_FIELD_BINDINGS,
);
@@ -3006,11 +3443,10 @@ export class BpmnScriptValidator {
});
}
} else if (!rule.parameters) {
- accept(
- 'error',
- `${capitalize(rule.description)} cannot declare an 'input' or 'output' parameter; ${PARAMETER_HOSTS_MESSAGE}`,
- { node: param, property: 'direction' },
- );
+ accept('error', noParameterHostMessage(rule.description), {
+ node: param,
+ property: 'direction',
+ });
} else if (IO_DIRECTION_SET.has(param.direction)) {
recognized.push(param);
} else {
@@ -3086,7 +3522,7 @@ export class BpmnScriptValidator {
(param) =>
accept(
'error',
- `Duplicate '${param.direction}' parameter '${param.name}'.`,
+ `duplicate '${param.direction}' parameter '${param.name}'`,
{ node: param, property: 'name' },
),
);
@@ -3149,13 +3585,16 @@ export class BpmnScriptValidator {
accept: ValidationAcceptor,
): void {
if (param.value === undefined) return;
- const subject = `${capitalize(param.direction)} '${param.name}'`;
+ const subject = `${param.direction} '${param.name}'`;
for (const node of AstUtils.streamAst(param.value)) {
if (isMapEntry(node) && node.key !== undefined && node.key.length === 0) {
accept(
'error',
- `A map entry's key cannot be empty; name the key its value is looked up by.`,
+ diagnosticText(
+ 'this map entry has an empty key',
+ 'help: name the key its value is looked up by',
+ ),
{ node, property: 'key' },
);
} else if (isLiteralString(node) && node.value.trim().length === 0) {
@@ -3206,15 +3645,20 @@ export class BpmnScriptValidator {
}
accept(
'error',
- `'on ${listener.event}' is a task listener, which only a user task has; ` +
- `${rule.description} takes ${formatWordList(EXECUTION_LISTENER_EVENTS)}.`,
+ diagnosticText(
+ `'on ${listener.event}' is a task listener, which only a user task has`,
+ `note: ${rule.description} takes ${formatWordList(EXECUTION_LISTENER_EVENTS)}`,
+ ),
{ node: listener, property: 'event' },
);
return false;
}
accept(
'error',
- `Unknown listener event '${listener.event}'; write ${formatWordList(listenerEventsFor(rule))}.`,
+ diagnosticText(
+ `unknown listener event '${listener.event}'`,
+ `help: write ${formatWordList(listenerEventsFor(rule))}`,
+ ),
{ node: listener, property: 'event' },
);
return false;
@@ -3228,7 +3672,7 @@ export class BpmnScriptValidator {
listener: Listener,
accept: ValidationAcceptor,
): void {
- const subject = `The 'on ${listener.event}' listener`;
+ const subject = `the 'on ${listener.event}' listener`;
const settings = settingsOf(listener.items);
// A fenced body binds the listener in place of its settings.
const refusal =
@@ -3266,7 +3710,7 @@ export class BpmnScriptValidator {
if (listener.script !== undefined) {
checkFencedScript(
listener.script,
- `The 'on ${listener.event}' listener`,
+ `the 'on ${listener.event}' listener`,
{ node: listener, property: 'script' },
accept,
);
@@ -3274,7 +3718,11 @@ export class BpmnScriptValidator {
}
this.checkAttributeKeys(
- settingsOf(listener.items),
+ settingsOf(listener.items).filter(
+ (setting) =>
+ listener.event !== 'timeout' ||
+ setting.key !== VALUE_DOCUMENTATION_KEYS.timer,
+ ),
LISTENER_BINDING_KEY_SET,
'a listener',
accept,
@@ -3283,10 +3731,10 @@ export class BpmnScriptValidator {
this.checkExactlyOneBinding(
settingsOf(listener.items),
LISTENER_BINDING_KEYS,
- `The 'on ${listener.event}' listener`,
+ `the 'on ${listener.event}' listener`,
{ node: listener, property: 'event' },
accept,
- ', or a fenced script body',
+ ', nor a fenced script body',
);
}
@@ -3367,17 +3815,21 @@ export class BpmnScriptValidator {
checkIfStatement = (stmt: IfStatement, accept: ValidationAcceptor): void => {
this.checkGatewaySettings(stmt, accept);
+ checkElseFailWord(stmt, accept);
+ // Beside `else fail` an empty branch is how a case carries on rather than
+ // failing, so it is no slip.
+ if (stmt.fail !== undefined) return;
this.checkEmptyBlock(
stmt.then,
'warning',
- "The 'if' branch has no steps.",
+ "the 'if' branch has no steps",
accept,
);
for (const elseIf of stmt.elseIfs) {
this.checkEmptyBlock(
elseIf.body,
'warning',
- "The 'else if' branch has no steps.",
+ "the 'else if' branch has no steps",
accept,
);
}
@@ -3385,7 +3837,7 @@ export class BpmnScriptValidator {
this.checkEmptyBlock(
stmt.elseBlock,
'warning',
- "The 'else' branch has no steps.",
+ "the 'else' branch has no steps",
accept,
);
}
@@ -3429,12 +3881,12 @@ export class BpmnScriptValidator {
for (const param of block.params) {
accept(
'error',
- blockMemberMessage(`An '${param.direction}' parameter`, 'configures'),
+ blockMemberMessage(`an '${param.direction}' parameter`, 'configures'),
{ node: param, property: 'direction' },
);
}
for (const listener of block.listeners) {
- accept('error', blockMemberMessage('A listener', 'observes'), {
+ accept('error', blockMemberMessage('a listener', 'observes'), {
node: listener,
property: 'event',
});
@@ -3448,7 +3900,10 @@ export class BpmnScriptValidator {
const kind = describeStatementKind(stmt);
accept(
'error',
- `${capitalize(kind)} named '${stmt.name}' has no flow steps: ${kind} needs at least one step on its main flow (handlers alone do not start it).`,
+ diagnosticText(
+ `${kind} named '${stmt.name}' has no flow steps`,
+ `note: ${kind} needs at least one step on its main flow, and handlers alone do not start it`,
+ ),
{ node: stmt, property: 'name' },
);
}
@@ -3481,10 +3936,11 @@ export class BpmnScriptValidator {
): void => {
this.checkGatewaySettings(stmt, accept);
stmt.branches.forEach((branch, index) => {
+ if (stmt.fail !== undefined && branch.condition !== undefined) return;
this.checkEmptyBlock(
branch.body,
'warning',
- `Branch ${index + 1} of the 'parallel' statement has no steps.`,
+ `branch ${index + 1} of the 'parallel' statement has no steps`,
accept,
);
});
@@ -3502,10 +3958,29 @@ export class BpmnScriptValidator {
property: 'otherwise',
});
}
+ const conditioned = stmt.branches.some(
+ (branch) => branch.condition !== undefined,
+ );
+ const unconditioned = stmt.branches.some(
+ (branch) => branch.condition === undefined && !branch.otherwise,
+ );
+ if (stmt.fail !== undefined) {
+ checkElseFailWord(stmt, accept);
+ const message = !conditioned
+ ? ELSE_FAIL_WITHOUT_CONDITION_MESSAGE
+ : unconditioned
+ ? ELSE_FAIL_BESIDE_UNCONDITIONED_MESSAGE
+ : fallbacks.length > 0
+ ? ELSE_FAIL_BESIDE_ELSE_MESSAGE
+ : undefined;
+ if (message !== undefined) {
+ accept('error', message, { node: stmt, property: 'fail' });
+ }
+ }
if (fallbacks.length === 0) return;
- const message = !hasConditionedBranch(stmt)
+ const message = !conditioned
? PARALLEL_ELSE_WITHOUT_CONDITION_MESSAGE
- : hasUnconditionedBranch(stmt)
+ : unconditioned
? PARALLEL_ELSE_BESIDE_UNCONDITIONED_MESSAGE
: undefined;
if (message !== undefined) {
@@ -3526,7 +4001,7 @@ export class BpmnScriptValidator {
this.checkEmptyBlock(
branch.body,
'warning',
- `Branch ${index + 1} of the 'await' statement has no steps.`,
+ `branch ${index + 1} of the 'await' statement has no steps`,
accept,
);
this.checkCatchTrigger(branch, accept);
@@ -3568,8 +4043,10 @@ export class BpmnScriptValidator {
if (isLinkCatch(target)) {
accept(
'error',
- `'goto ${targetName}' cannot target an awaited link: a link catch is ` +
- "entered by 'emit link' of the same name, not by a sequence flow.",
+ diagnosticText(
+ `'goto ${targetName}' targets an awaited link`,
+ "note: a link catch is entered by 'emit link' of the same name, not by a sequence flow",
+ ),
{ node: goto, property: 'target' },
);
return;
@@ -3593,8 +4070,7 @@ export class BpmnScriptValidator {
): void => {
this.checkAttributeBlock(call, accept);
this.checkCallProcessAttribute(call, accept);
- this.checkBindingAttribute(call, accept);
- this.checkBindingVersionExclusion(call, 'A call', accept);
+ this.checkVersionPin(call, 'a call', accept);
this.checkCallMapperExclusion(call, accept);
this.checkCallMappingDuplicates(call, accept);
};
@@ -3606,52 +4082,43 @@ export class BpmnScriptValidator {
if (settingsOf(call.items).some((a) => a.key === 'process')) return;
accept(
'error',
- `A call must name the process it starts: add process: "".`,
+ diagnosticText(
+ "this call has no 'process' setting naming the process it starts",
+ `help: add 'process: ""'`,
+ ),
{ node: call, property: 'name' },
);
}
/** Bare `version` parses as a variable reference, quoted as a string; both read the same text. */
- private checkBindingAttribute(
+ private checkVersionPin(
owner: VersionPinnedElement,
+ subject: string,
accept: ValidationAcceptor,
): void {
- const bindingAttr = settingsOf(owner.items).find(
- (a) => a.key === 'binding',
- );
- if (!bindingAttr) {
- return;
- }
- const value = bindingValueText(bindingAttr.value);
- if (value !== undefined && CALL_BINDING_VALUE_SET.has(value)) {
- return;
- }
- if (value === 'version') {
+ const settings = settingsOf(owner.items);
+ const binding = settings.find((a) => a.key === 'binding');
+ if (binding === undefined) return;
+ const value = bindingValueText(binding.value);
+ if (value === undefined || !CALL_BINDING_VALUE_SET.has(value)) {
accept(
'error',
- `Write 'version: ' instead of 'binding: version'.`,
- { node: bindingAttr, property: 'value' },
+ value === 'version'
+ ? diagnosticText(
+ "'binding: version' is not a binding mode",
+ "help: write 'version: '",
+ )
+ : `setting 'binding' must be ${formatWordList(CALL_BINDING_VALUES)}`,
+ { node: binding, property: 'value' },
);
- return;
}
- accept(
- 'error',
- `Setting 'binding' must be ${formatWordList(CALL_BINDING_VALUES)}.`,
- { node: bindingAttr, property: 'value' },
- );
- }
-
- private checkBindingVersionExclusion(
- owner: VersionPinnedElement,
- subject: string,
- accept: ValidationAcceptor,
- ): void {
- const hasBinding = settingsOf(owner.items).some((a) => a.key === 'binding');
- const hasVersion = settingsOf(owner.items).some((a) => a.key === 'version');
- if (hasBinding && hasVersion) {
+ if (settings.some((a) => a.key === 'version')) {
accept(
'error',
- `${subject} cannot combine 'binding' and 'version'; use 'version: ' to pin a specific version, or ${BINDING_MODE_PHRASES.join('/')} for the other modes.`,
+ diagnosticText(
+ `${subject} combines 'binding' and 'version'`,
+ `help: write 'version: ' to pin a specific version, or ${formatPlainWordList(BINDING_MODE_PHRASES)} for the other modes`,
+ ),
{ node: owner, property: 'name' },
);
}
@@ -3665,7 +4132,7 @@ export class BpmnScriptValidator {
checkAtMostOneBinding(
settingsOf(call.items),
Object.values(CALL_MAPPER_KEY_BY_KIND),
- 'A call',
+ 'a call',
{ node: call, property: 'name' },
accept,
);
@@ -3684,8 +4151,11 @@ export class BpmnScriptValidator {
accept(
'error',
mapping.all
- ? `Duplicate '${mapping.direction} *' mapping; a direction can copy every variable only once.`
- : `Duplicate '${mapping.direction}' mapping target '${mapping.target}'.`,
+ ? diagnosticText(
+ `duplicate '${mapping.direction} *' mapping`,
+ 'note: a direction can copy every variable only once',
+ )
+ : `duplicate '${mapping.direction}' mapping target '${mapping.target}'`,
mapping.all
? { node: mapping }
: { node: mapping, property: 'target' },
@@ -3730,7 +4200,7 @@ export class BpmnScriptValidator {
this.checkEmptyBlock(
handler.body,
'warning',
- 'The event handler has no steps.',
+ 'the event handler has no steps',
accept,
);
};
@@ -3747,7 +4217,7 @@ export class BpmnScriptValidator {
if (!code) {
accept(
'error',
- nameRequiredMessage(`A ${handler.trigger} handler`, handler.trigger),
+ nameRequiredMessage(`a ${handler.trigger} handler`, handler.trigger),
{ node: handler, property: 'trigger' },
);
}
@@ -3768,13 +4238,7 @@ export class BpmnScriptValidator {
}
this.checkConditionPayload(handler, rule, 'handler', accept);
-
- this.checkTimerClause(
- handler,
- rule.timer,
- particleOnlyMessage("'on timer'"),
- accept,
- );
+ this.checkTimerClause(handler, rule.timer, 'handler', accept);
const handlerBindings = caughtBindingsOf(handler.items);
if (rule.parens === 'forbidden' && handlerBindings.length > 0) {
@@ -3783,7 +4247,10 @@ export class BpmnScriptValidator {
'error',
handler.trigger === 'compensation'
? COMPENSATION_BINDINGS_MESSAGE
- : `'(code: c)' bindings belong to error and escalation handlers; a ${handler.trigger} carries no code.`,
+ : diagnosticText(
+ `a ${handler.trigger} carries no code to bind`,
+ "note: '(code: c)' bindings belong to error and escalation handlers",
+ ),
{ node: binding.node, property: 'key' },
);
}
@@ -3793,30 +4260,37 @@ export class BpmnScriptValidator {
private checkConditionPayload(
node: CatchHeader | OnHandler | StartEvent,
rule: TriggerPayloadRule,
- position: ConditionPosition,
+ position: PayloadPosition,
accept: ValidationAcceptor,
): void {
- const { subject, clause, only } = CONDITION_PHRASING[position];
+ const { subject, clause, only } = PAYLOAD_PHRASING[position];
const form = `${clause}(amount > 100)`;
const payload = payloadItemOf(node.items);
if (rule.parens === 'condition' && payload === undefined) {
- accept('error', `${subject} needs its condition: '${form}'.`, {
- node,
- property: 'trigger',
- });
+ accept(
+ 'error',
+ diagnosticText(`${subject} has no condition`, `help: write '${form}'`),
+ {
+ node,
+ property: 'trigger',
+ },
+ );
}
if (node.trigger === 'condition' && hasQuotedPayload(node.items)) {
accept(
'error',
- `${subject} takes no code string; write the condition itself: '${form}'.`,
+ diagnosticText(
+ `${subject} holds a quoted string instead of a condition`,
+ `help: write the condition itself: '${form}'`,
+ ),
{ node: payload!, property: 'value' },
);
}
if (node.trigger !== 'condition' && hasExpressionPayload(node.items)) {
- accept('error', `Only ${only} takes a condition expression.`, {
+ accept('error', `only ${only} takes a condition expression`, {
node: payload!,
property: 'value',
});
@@ -3830,13 +4304,16 @@ export class BpmnScriptValidator {
private checkTimerClause(
node: CatchHeader | OnHandler | StartEvent,
required: boolean,
- particleOnly: string,
+ position: PayloadPosition,
accept: ValidationAcceptor,
): void {
if (!required) {
const keyed = timerParticleOf(node.items);
if (keyed !== undefined) {
- accept('error', particleOnly, { node: keyed.node, property: 'key' });
+ accept('error', particleOnlyMessage(PAYLOAD_PHRASING[position].timer), {
+ node: keyed.node,
+ property: 'key',
+ });
}
return;
}
@@ -3884,7 +4361,10 @@ export class BpmnScriptValidator {
} else if (known === undefined) {
accept(
'error',
- `Unknown timer particle '${particle}'; write ${formatWordList(TIMER_PARTICLES)}.`,
+ diagnosticText(
+ `unknown timer particle '${particle}'`,
+ `help: write ${formatWordList(TIMER_PARTICLES)}`,
+ ),
{ node: listener, property: 'particle' },
);
} else if (listener.time !== undefined) {
@@ -3926,8 +4406,10 @@ export class BpmnScriptValidator {
if (timer.particle === 'every' && !hasFlag(handler.items, 'alongside')) {
accept(
'warning',
- 'A repeating timer that interrupts its scope fires at most once: ' +
- "add 'alongside' to let it repeat, or give it a duration instead.",
+ diagnosticText(
+ 'a repeating timer that interrupts its scope fires at most once',
+ "help: add 'alongside' to let it repeat, or give it a duration instead",
+ ),
{ node: timer.node },
);
}
@@ -3953,7 +4435,11 @@ export class BpmnScriptValidator {
}
accept(
'error',
- 'An event handler belongs directly in the body of a process, a subprocess, an attempt block, or another event handler: it handles events for that whole scope, not for a single branch.',
+ diagnosticText(
+ 'this event handler sits inside a branch or loop body',
+ 'note: a handler handles events for a whole scope, not for a single branch',
+ 'note: it belongs directly in the body of a process, a subprocess, an attempt block, or another event handler',
+ ),
{ node: handler },
);
}
@@ -3970,12 +4456,41 @@ export class BpmnScriptValidator {
if (hasNonHandlerAfter) {
accept(
'error',
- 'Event handlers read like catch blocks: move it after the last step of this body.',
+ diagnosticText(
+ 'this event handler comes before a step of its body',
+ 'note: event handlers read like catch blocks',
+ 'help: move it after the last step of this body',
+ ),
{ node: handler },
);
}
}
+ /**
+ * A field or property key is any string to the engine, but an 'input' or
+ * 'output' name is the variable it sets, which an expression reads plain.
+ */
+ checkIoParameterName(param: IoParameter, accept: ValidationAcceptor): void {
+ if (
+ (param.direction !== INPUT_DIRECTION &&
+ param.direction !== OUTPUT_DIRECTION) ||
+ GrammarUtils.findNodeForProperty(param.$cstNode, 'name')?.text.startsWith(
+ '`',
+ ) !== true
+ ) {
+ return;
+ }
+ accept(
+ 'error',
+ diagnosticText(
+ `'${param.name}' in backticks is not a variable`,
+ `note: an '${param.direction}' parameter names the variable it sets`,
+ 'note: backticks spell a key, or the name of a step, a process or a code',
+ ),
+ { node: param, property: 'name' },
+ );
+ }
+
private checkHandlerBindings(
handler: OnHandler,
accept: ValidationAcceptor,
@@ -3993,7 +4508,11 @@ export class BpmnScriptValidator {
// `code: "X"` is a setting, not a binding, so nothing gets bound.
accept(
'error',
- `A catch binding names the variable the caught ${binding.field} lands in, not a value: write '${binding.field}: '.`,
+ diagnosticText(
+ 'this catch binding names a value instead of a variable',
+ `note: a catch binding names the variable the caught ${binding.field} lands in`,
+ `help: write '${binding.field}: '`,
+ ),
{ node: binding.node, property: 'value' },
);
}
@@ -4069,11 +4588,11 @@ export class BpmnScriptValidator {
* beside a coded one.
*/
private checkHandlerDuplicates(
- process: Process,
+ nodes: readonly AstNode[],
accept: ValidationAcceptor,
): void {
const candidates: OnHandler[] = [];
- for (const node of AstUtils.streamAst(process)) {
+ for (const node of nodes) {
if (!isOnHandler(node)) continue;
if (!ON_TRIGGERS_SET.has(node.trigger)) continue;
// Timer and condition key no subscription name, and two deadlines in one
@@ -4127,42 +4646,37 @@ export class BpmnScriptValidator {
stmt: ThrowStatement,
accept: ValidationAcceptor,
): void => {
- this.checkAttributeBlock(stmt, accept);
-
- if (stmt.trigger === undefined) return;
-
- if (!THROW_TRIGGERS_SET.has(stmt.trigger)) {
- accept('error', throwTriggerMessage(stmt.trigger), {
- node: stmt,
- property: 'trigger',
- });
- return;
- }
- checkThrowEmitCode(stmt, 'A thrown', 'throw', accept);
- checkThrowEmitBinding(stmt, 'a thrown', accept);
+ this.checkRaisedEvent(stmt, accept);
};
checkEmitStatement = (
stmt: EmitStatement,
accept: ValidationAcceptor,
): void => {
- this.checkAttributeBlock(stmt, accept);
-
- if (stmt.trigger === undefined) return;
+ if (this.checkRaisedEvent(stmt, accept) && stmt.trigger === 'link') {
+ this.checkLinkThrowItems(stmt, accept);
+ }
+ };
- if (!EMIT_TRIGGERS_SET.has(stmt.trigger)) {
- accept('error', emitTriggerMessage(stmt.trigger), {
+ /** Returns whether the trigger is one the statement raises. */
+ private checkRaisedEvent(
+ stmt: ThrowStatement | EmitStatement,
+ accept: ValidationAcceptor,
+ ): boolean {
+ this.checkAttributeBlock(stmt, accept);
+ if (stmt.trigger === undefined) return false;
+ const raise = RAISE_PHRASING[stmt.$type];
+ if (!raise.triggers.has(stmt.trigger)) {
+ accept('error', raise.triggerMessage(stmt.trigger), {
node: stmt,
property: 'trigger',
});
- return;
- }
- checkThrowEmitCode(stmt, 'An emitted', 'emit', accept);
- checkThrowEmitBinding(stmt, 'an emitted', accept);
- if (stmt.trigger === 'link') {
- this.checkLinkThrowItems(stmt, accept);
+ return false;
}
- };
+ checkThrowEmitCode(stmt, raise, accept);
+ checkThrowEmitBinding(stmt, raise, accept);
+ return true;
+ }
/** A link throw gets no activity, so its settings and listeners parse into nothing. */
private checkLinkThrowItems(
@@ -4171,7 +4685,7 @@ export class BpmnScriptValidator {
): void {
for (const setting of configuredSettingsOf(stmt)) {
if (!ENGINE_KEY_SET.has(setting.key)) continue;
- accept('error', linkThrowNeverRunsMessage(`Setting '${setting.key}'`), {
+ accept('error', linkThrowNeverRunsMessage(`setting '${setting.key}'`), {
node: setting,
property: 'key',
});
@@ -4179,7 +4693,7 @@ export class BpmnScriptValidator {
for (const listener of stmt.listeners) {
accept(
'error',
- linkThrowNeverRunsMessage(`The 'on ${listener.event}' listener`),
+ linkThrowNeverRunsMessage(`the 'on ${listener.event}' listener`),
{ node: listener },
);
}
@@ -4199,7 +4713,12 @@ export class BpmnScriptValidator {
* trigger word.
*/
checkParenValue = (value: ParenValue, accept: ValidationAcceptor): void => {
- const owner = value.$container;
+ // Beside a condition, `checkConditionItem` refuses it.
+ if (value.$containerProperty !== 'items') return;
+ const owner = value.$container as Exclude<
+ ParenValue['$container'],
+ ElseIf | ParallelBranch
+ >;
if (payloadItemOf(owner.items) !== value) {
accept('error', SECOND_PAREN_VALUE_MESSAGE, { node: value });
return;
@@ -4247,7 +4766,7 @@ export class BpmnScriptValidator {
accept(
'error',
nameRequiredMessage(
- `An awaited ${catchEvent.trigger}`,
+ `an awaited ${catchEvent.trigger}`,
catchEvent.trigger,
),
{ node: catchEvent, property: 'trigger' },
@@ -4255,13 +4774,7 @@ export class BpmnScriptValidator {
}
this.checkConditionPayload(catchEvent, rule, 'catch', accept);
-
- this.checkTimerClause(
- catchEvent,
- rule.timer,
- particleOnlyMessage("'await timer'"),
- accept,
- );
+ this.checkTimerClause(catchEvent, rule.timer, 'catch', accept);
}
/**
@@ -4289,7 +4802,10 @@ export class BpmnScriptValidator {
if (declaredNames.has(decl.name)) {
accept(
'error',
- `'${decl.name}' is already declared in this process; '${decl.kind}(${decl.name})' would be ambiguous.`,
+ diagnosticText(
+ `'${decl.name}' is already declared in this process`,
+ `note: '${decl.kind}(${printName(decl.name)})' would be ambiguous`,
+ ),
{ node: decl, property: 'name' },
);
} else {
@@ -4306,7 +4822,10 @@ export class BpmnScriptValidator {
if (owner.name === decl.name) continue;
accept(
'error',
- `${capitalize(decl.kind)} code '${code}' is already declared by '${owner.name}'; two declarations cannot share a code.`,
+ diagnosticText(
+ `${decl.kind} code '${code}' is already declared by '${owner.name}'`,
+ 'note: two declarations cannot share a code',
+ ),
{ node: decl, property: 'name' },
);
}
@@ -4344,13 +4863,13 @@ export class BpmnScriptValidator {
} else if (!isLiteralString(setting.value)) {
accept(
'error',
- `An ${decl.kind} declaration's ${setting.key} must be a quoted string.`,
+ `the ${setting.key} of an ${decl.kind} declaration is not a quoted string`,
{ node: setting, property: 'value' },
);
} else if (setting.value.value.length === 0) {
accept(
'error',
- `An ${decl.kind} declaration's ${setting.key} cannot be empty.`,
+ `the ${setting.key} of an ${decl.kind} declaration is empty`,
{ node: setting, property: 'value' },
);
}
@@ -4358,8 +4877,29 @@ export class BpmnScriptValidator {
}
}
-function collectExpressions(process: Process): Expr[] {
- return AstUtils.streamAst(process).filter(isExpr).toArray();
+function isQuotedOutsideCode(ref: VarRef): boolean {
+ return (
+ ref.ref.$refNode?.text.startsWith('`') === true && !isCodePosition(ref)
+ );
+}
+
+/** A name in backticks can spell text that no element id may hold. */
+function checkEngineIds(
+ named: ReadonlyArray,
+ accept: ValidationAcceptor,
+): void {
+ for (const node of named) {
+ if (node.name === undefined || ENGINE_ID_TEXT.test(node.name)) continue;
+ accept(
+ 'error',
+ diagnosticText(
+ `'${node.name}' is not an id Operaton deploys`,
+ "note: the name becomes the element's id, and Operaton validates every id against 'BPMN20.xsd' as an 'xs:ID'",
+ "note: an id is ASCII letters, digits, '_', '-' and '.', starting with a letter or '_'",
+ ),
+ { node, property: 'name' },
+ );
+ }
}
/** Exported so the printer can warn about an imported id. */
@@ -4380,10 +4920,6 @@ function enclosingContainerName(node: NamedStatement): string | undefined {
return container?.name;
}
-function capitalize(text: string): string {
- return text.charAt(0).toUpperCase() + text.slice(1);
-}
-
function checkFencedScript(
raw: string,
subject: string,
@@ -4395,37 +4931,48 @@ function checkFencedScript(
if (scriptFormatOf(tag) === undefined) {
accept(
'error',
- `${subject} has an unsupported language tag '${tag}'. Use ${formatWordList(Object.keys(SCRIPT_FORMAT_ALIASES))}.`,
+ diagnosticText(
+ `${subject} has an unsupported language tag '${tag}'`,
+ `help: use ${formatWordList(Object.keys(SCRIPT_FORMAT_ALIASES))}`,
+ ),
target,
);
}
+ // `ScriptUtil.getScript` checks the source for null only, so the engine
+ // deploys an empty body and evaluates it to nothing.
if (code.trim().length === 0) {
- accept('error', `${subject} has an empty script body.`, target);
+ accept(
+ 'warning',
+ diagnosticText(
+ `${subject} has an empty script body`,
+ 'note: the engine runs it and it does nothing',
+ ),
+ target,
+ );
}
}
export function quotedCodeMessage(trigger: string, text: string): string {
- const spellable = ID_TEXT.test(text);
- const declaration = spellable
- ? `${trigger} ${text}`
- : `${trigger} (code: ${JSON.stringify(text)})`;
- const use = spellable ? text : '';
- return (
- `An ${trigger} code is a declared name, not quoted text. ` +
- `Declare '${declaration}' in the process header and write '${trigger}(${use})'.`
+ const name = printName(text);
+ return diagnosticText(
+ `an ${trigger} code is a declared name, not quoted text`,
+ `help: declare '${trigger} ${name}' in the process header and write '${trigger}(${name})'`,
);
}
function barewordNameMessage(trigger: string, text: string): string {
- return (
- `A ${trigger} name is the text the engine matches by name, not a declared ` +
- `name. Write '${trigger}("${text}")'.`
+ return diagnosticText(
+ `a ${trigger} name is the text the engine matches by name, not a declared name`,
+ `help: write '${trigger}("${text}")'`,
);
}
function unknownTriggerMessage(word: string, legal: readonly string[]): string {
- return `Unknown event kind '${word}'; write ${formatWordList(legal)}.`;
+ return diagnosticText(
+ `unknown event kind '${word}'`,
+ `help: write ${formatWordList(legal)}`,
+ );
}
/**
@@ -4433,10 +4980,9 @@ function unknownTriggerMessage(word: string, legal: readonly string[]): string {
* message names both readings.
*/
export function unknownDeclarationKindMessage(word: string): string {
- return (
- `Unknown declaration kind '${word}'; write ` +
- `${formatWordList([...DECLARED_CODE_TRIGGERS])}, or a step keyword if a ` +
- 'step was meant.'
+ return diagnosticText(
+ `unknown declaration kind '${word}'`,
+ `help: write ${formatWordList([...DECLARED_CODE_TRIGGERS])}, or a step keyword if a step was meant`,
);
}
@@ -4452,41 +4998,45 @@ export function onTriggerMessage(word: string): string {
export function startTriggerMessage(word: string): string {
if (word === 'error' || word === 'escalation') {
- return (
- `A process cannot start on an ${word}: the engine ignores the trigger ` +
- 'and starts the process as if none were written. Catch it with ' +
- `'on ${word}' inside the scope that raises it.`
+ return diagnosticText(
+ `a process cannot start on an ${word}`,
+ 'note: the engine ignores the trigger and starts the process as if none were written',
+ `help: catch it with 'on ${word}' inside the scope that raises it`,
);
}
if (word === 'compensation') {
- return (
- "A process cannot start on compensation: it undoes a subprocess's " +
- "completed work, so it belongs in an 'on compensation' block inside " +
- 'that subprocess.'
+ return diagnosticText(
+ 'a process cannot start on compensation',
+ "note: compensation undoes a subprocess's completed work",
+ "help: write it as an 'on compensation' block inside that subprocess",
);
}
if (word === 'conditional') {
return CONDITIONAL_TYPO_MESSAGE;
}
- return `Unknown event kind '${word}'; a start event supports ${formatWordList(START_TRIGGERS)}.`;
+ return diagnosticText(
+ `unknown event kind '${word}' on a start event`,
+ `help: write ${formatWordList(START_TRIGGERS)}`,
+ );
}
export function alongsideMessage(trigger: string): string {
if (trigger === 'compensation') return COMPENSATION_ALONGSIDE_MESSAGE;
if (trigger === 'cancel') return CANCEL_ALONGSIDE_MESSAGE;
- return (
- 'An error always interrupts: the handler takes over from the failed ' +
- "scope; 'alongside' is only available for escalations."
+ return diagnosticText(
+ "an error handler cannot run 'alongside'",
+ 'note: an error always interrupts, and the handler takes over from the failed scope',
+ "note: 'alongside' is only available for escalations",
);
}
export function endTriggerMessage(word: string): string {
if (THROW_TRIGGERS_SET.has(word)) {
- const article = /^[aeiou]/.test(word) ? 'An' : 'A';
- return (
- `${article} ${word} is raised with 'throw', not on an end: write ` +
- `'throw ${word}' in place of this end. ` +
- END_TRIGGERS_MESSAGE
+ const article = /^[aeiou]/.test(word) ? 'an' : 'a';
+ return diagnosticText(
+ `${article} ${word} is raised with 'throw', not on an end`,
+ END_TRIGGERS_NOTE,
+ `help: write 'throw ${word}' in place of this end`,
);
}
if (word === 'timer') {
@@ -4495,19 +5045,19 @@ export function endTriggerMessage(word: string): string {
if (word === 'condition' || word === 'conditional') {
return END_CONDITION_MESSAGE;
}
- return (
- `Unknown event kind '${word}'. ${END_TRIGGERS_MESSAGE} Every other kind ` +
- "is raised with 'throw'."
+ return diagnosticText(
+ `unknown event kind '${word}' on an end event`,
+ END_TRIGGERS_NOTE,
+ "note: every other kind is raised with 'throw'",
);
}
export function startMessageExpressionMessage(name: string): string {
- return (
- `A message start name cannot contain an expression ("${name}"): the ` +
- 'engine rejects one there, because a process that has not started yet ' +
- 'has no variables to evaluate it against. Give the start a fixed name; ' +
- "an expression belongs on an 'on message' handler or an 'await message', " +
- 'which run once the process has variables.'
+ return diagnosticText(
+ `the message start name "${name}" contains an expression`,
+ 'note: a process that has not started yet has no variables to evaluate it against, so the engine rejects it',
+ "note: an expression belongs on an 'on message' handler or an 'await message', which run once the process has variables",
+ 'help: give the start a fixed name',
);
}
@@ -4519,14 +5069,22 @@ export function throwTriggerMessage(word: string): string {
return CANCEL_NOT_RAISED_MESSAGE;
}
if (word === 'link') {
- return "A link continues at its catch rather than ending the path; write 'emit link'.";
+ return diagnosticText(
+ 'a link cannot be thrown',
+ 'note: a link continues at its catch instead of ending the path',
+ "help: write 'emit link'",
+ );
}
return unknownTriggerMessage(word, THROW_TRIGGERS);
}
export function emitTriggerMessage(word: string): string {
if (word === 'error') {
- return "An error always aborts its path; write 'throw error'.";
+ return diagnosticText(
+ 'an error cannot be emitted',
+ 'note: an error always aborts its path',
+ "help: write 'throw error'",
+ );
}
if (word === 'compensate') {
return COMPENSATE_TYPO_MESSAGE;
@@ -4544,11 +5102,12 @@ export function catchTriggerMessage(word: string): string {
if (word === 'cancel') {
return CANCEL_NOT_AWAITED_MESSAGE;
}
- return (
- `Unknown event kind '${word}'; intermediate catch supports ${formatWordList(CATCH_TRIGGERS)}. ` +
- "An error or an escalation is raised with 'throw'/'emit', compensation " +
- "is a subprocess's undo block, and a cancel is written on the end that " +
- `gives up an 'attempt' block.`
+ return diagnosticText(
+ `unknown event kind '${word}' on an intermediate catch`,
+ `note: an intermediate catch supports ${formatWordList(CATCH_TRIGGERS)}`,
+ "note: an error or an escalation is raised with 'throw' or 'emit'",
+ "note: compensation is a subprocess's undo block",
+ "note: a cancel is written on the end that gives up an 'attempt' block",
);
}
@@ -4608,25 +5167,24 @@ function cancelHandlerFor(block: SubProcess): OnHandler | undefined {
}
function cancelHostMessage(host: Statement): string {
- return (
- `A cancel handler can only attach to an 'attempt' block: it catches ` +
- `that block being given up; '${targetStatementName(host)}' is ${describeStatementKind(host)}.`
+ return diagnosticText(
+ `this cancel handler attaches to '${targetStatementName(host)}', which is ${describeStatementKind(host)}`,
+ "note: a cancel handler can only attach to an 'attempt' block, since it catches that block being given up",
);
}
export function cancelEndWithoutHandlerMessage(name: string): string {
- return (
- `'${name}' gives itself up but nothing catches it: the engine stops with ` +
- `an error the first time that end is reached. Write 'on ${name}: cancel ` +
- `{ ... }' beside the block to say what happens then.`
+ return diagnosticText(
+ `'${name}' gives itself up but nothing catches it`,
+ 'note: the engine stops with an error the first time that end is reached',
+ `help: write 'on ${name}: cancel { ... }' beside the block to say what happens then`,
);
}
export function cancelHandlerWithoutEndMessage(name: string): string {
- return (
- `Nothing inside '${name}' gives it up, so this handler never runs: write ` +
- `'end cancel' on the path that should give the block up, or ` +
- 'remove the handler.'
+ return diagnosticText(
+ `nothing inside '${name}' gives it up, so this handler never runs`,
+ "help: write 'end