Classifies the effects a body performs, for the two features that need to reason about them: compiler contracts and Avenx Rewind.
ContractValidator has always asked "does this expression have side
effects?" as a yes/no question. Rewind asks a sharper one: which effects
are there, where are they, and can a rewind put them back? A state.count++
is a side effect and is perfectly reversible; a localStorage.setItem() is
a side effect and is not. Both questions are answered from the same pattern
table so the two features can never disagree about what an effect is.
What this is not
It is not a JavaScript parser. It is a string- and comment-aware scan, in
the same spirit as atlas/resolve.js, and it is deliberately conservative:
a pattern it cannot classify is reported, never assumed harmless. The one
place that judgement is inverted is the tail effect — a request whose
result the action returns or awaits is the very thing whose failure drives
the rewind, so flagging it would warn about the intended design.
- Source:
Members
(static, constant) EffectKind :string
How an effect relates to a rewind.
Type:
- string
- Source:
(static, constant) IMPURE_PATTERNS :Array:.<RegExp:>
Known side-effecting / impure patterns in expressions.
This is the pure contract's list and its meaning is unchanged: any of
these makes an expression impure, assignment included.
Type:
- Source:
(static, constant) NON_DETERMINISTIC_PATTERNS :Array:.<RegExp:>
Known non-deterministic identifiers and expressions.
Moved here from ContractValidator so that the deterministic contract and
any future consumer read the same list.
Type:
- Source:
(inner, constant) CONTINUATION_PATTERN :RegExp
Promise continuations, where a state write lands outside the transaction.
Type:
- RegExp
- Source:
(inner, constant) IRREVERSIBLE_PATTERNS :Array:.<{kind:: string:, pattern:: RegExp:, label:: string:}>
The effect patterns Rewind reports, in scan order.
test is applied to the masked source; label is what a diagnostic prints.
Ordered longest-prefix-first so sessionStorage is not reported as
Storage twice.
Type:
- Source:
(inner, constant) REQUEST_PATTERN :RegExp
Request-like calls, which are only irreversible when their result escapes the action unobserved.
Type:
- RegExp
- Source:
Methods
(static) findDeferredWrites(source, optionsopt) → {Array:.<{kind:: string:, text:: string:, line:: number:}>}
Finds promise continuations, where a state write escapes the transaction.
A write made inside .then(...) runs after the action has already returned,
so the journal — which follows the dynamic extent of the call — never sees
it. That is a completeness problem, not an irreversibility one, which is why
it is reported separately, under AVX_W42.
Parameters:
| Name | Type | Attributes | Description | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
source |
string | The action body source. |
|||||||||
options |
object |
<optional> |
Scan options. Properties
|
- Source:
Returns:
The continuations.
(static) findIrreversibleEffects(source, optionsopt) → {Array:.<{kind:: string:, label:: string:, text:: string:, line:: number:}>}
Finds every effect in a body that a rewind cannot undo.
Returns descriptors rather than booleans because the diagnostic's whole value is naming what will be left behind, and where.
Parameters:
| Name | Type | Attributes | Description | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
source |
string | The action body source. |
|||||||||
options |
object |
<optional> |
Scan options. Properties
|
- Source:
Returns:
The effects, in source order.
(static) maskLiterals(source) → {string}
Masks string literals, template literals and comments.
Without this an emit inside a string, or a document. written in a
comment explaining why it is not used, would be reported as an effect.
Parameters:
| Name | Type | Description |
|---|---|---|
source |
string | The body source. |
- Source:
Returns:
The source with literals and comments blanked, same length.
- Type
- string
(inner) blank(text) → {string}
Replaces a run of source with spaces, preserving newlines so that every offset in the masked text still points at the same line as in the original.
Parameters:
| Name | Type | Description |
|---|---|---|
text |
string | The run to blank out. |
- Source:
Returns:
The blanked run.
- Type
- string
(inner) isTailPosition(masked, offset) → {boolean}
Whether the statement containing an offset is returned or awaited.
The transaction outcome is the value the action hands back, so a request
in that position is not a loose effect — it is the mechanism. Scans back to
the nearest statement boundary rather than parsing, which is enough to tell
return api.save() from api.save();.
Parameters:
| Name | Type | Description |
|---|---|---|
masked |
string | The masked body source. |
offset |
number | Where the call starts. |
- Source:
Returns:
True when the call's result is returned or awaited.
- Type
- boolean
(inner) lineAt(source, offset) → {number}
Turns an offset into a 1-based line number within the body.
Parameters:
| Name | Type | Description |
|---|---|---|
source |
string | The body source. |
offset |
number | A character offset. |
- Source:
Returns:
The 1-based line.
- Type
- number