Turns Avenx expression source text into resolved semantic references.
This is the part of Atlas that cannot be had for free. The compiler keeps template expressions, computed expressions and action bodies as source text all the way to evaluation, which is exactly what makes Atlas possible — and it means Atlas has to read that text itself.
Two passes, deliberately:
- collectLocals finds every name the body binds itself —
const,let,var, function and arrow parameters,catchbindings, destructuring patterns. It runs first so that a reference appearing ahead of the declaration that shadows it is still recognised as local. - scanReferences walks the text and records every member chain, what was done to it (read, write, invoke) and where it sat in the source.
resolveReference then maps a chain onto a declaration in scope.
What this is not
It is not a JavaScript parser, and an action body is arbitrary JavaScript. The scanner is string- and comment-aware and understands member access, optional chaining, computed members, calls, assignment and destructuring — which covers the shapes Avenx components actually contain. Everything it cannot follow is reported as an UnresolvedReason, never dropped and never guessed. The house rule for this file is that a missing edge must be visible somewhere; an uncertain answer beats a confidently wrong one.
- Source:
Members
(static, constant) AMBIENT_ROOTS :Set:.<string:>
Identifiers that resolve to something outside the application's own model.
The first group mirrors the sandbox's allowlist in
lib/core/security/sandbox.js — an expression may legitimately name these
and they are not application state. The second group is the scope the
runtime injects around a template expression or an action body.
Type:
- Source:
(static, constant) BRIDGE_BUILTINS :Set:.<string:>
Members every bridge exposes as protocol rather than declaring.
declaredMembers() in BridgeParser appends the same three, so accessing one
is not an unknown member.
Type:
- Source:
(static, constant) COLLECTION_METHODS :Set:.<string:>
Collection methods that yield another collection of the same elements.
Type:
- Source:
(static, constant) ELEMENT_METHODS :Set:.<string:>
Collection methods that yield one element rather than another collection.
const item = this.items.find(...) binds an element of items, so a later
item.qty = n is a write to items. Which element is not knowable, which
is why an alias resolved this way is only ever possible.
Type:
- Source:
(static, constant) MUTATING_METHODS :Set:.<string:>
Methods that mutate the receiver rather than returning a new value.
cart.items.push(item) is a write to cart.items, and modelling it as a
read would make avenx impact cart.items miss the code that changes it —
the single most important question the command answers.
Type:
- Source:
(inner, constant) ASSIGN_OPERATORS :Array:.<string:>
Assignment operators, longest first so ??= is matched before ?.
Type:
- Source:
(inner, constant) DECLARATION_KEYWORDS :Set:.<string:>
Statements that begin a binding.
Type:
- Source:
Methods
(static) collectLocals(code) → {Set:.<string:>}
Collects every name the body binds locally.
Runs before reference scanning so that a use appearing textually before its declaration is still treated as local. Scoping is deliberately flat: a name declared anywhere in the body shadows an application declaration everywhere in it. That over-approximates shadowing, which is the safe direction — Atlas loses an edge and says so, rather than inventing one.
Parameters:
| Name | Type | Description |
|---|---|---|
code |
string | The expression or action body. |
- Source:
Returns:
Locally bound names.
(static) formatPath(segments) → {string}
Formats a member path for display, with [] for element access.
Parameters:
| Name | Type | Description |
|---|---|---|
segments |
Array:.<string:> | The path segments. |
- Source:
Returns:
A dotted path, e.g. items[].qty.
- Type
- string
(static) patternBindings(pattern) → {Object}
Collects every identifier bound inside a destructuring pattern.
Handles { a, b: c, d = 1, ...rest } and [x, , y], including nesting.
Renaming (b: c) binds c, and the key b is reported separately as a
member read of the initialiser by scanReferences.
Parameters:
| Name | Type | Description |
|---|---|---|
pattern |
string | The pattern text, brackets included. |
- Source:
Returns:
What it binds.
- Type
- Object
(static) resolveBridgeMember(descriptor, segments, ownerId) → {Object|null}
Resolves a member access against a bridge's declared surface.
The compiler already resolves these names once, to warn about members a bridge does not declare (AVX_W37). Atlas keeps the answer instead of discarding it, which is what lets a query cross a file boundary.
Parameters:
| Name | Type | Description |
|---|---|---|
descriptor |
object | A bridge descriptor from BridgeParser. |
segments |
Array:.<string:> | The member path. |
ownerId |
string | The bridge's node id. |
- Source:
Returns:
The declaration, or null.
- Type
- Object | null
(static) resolveReference(ref, scope) → {Object}
Maps a scanned reference onto a declaration in scope.
The result names a declared symbol, not a property path: a read of
cart.items[2].qty resolves to the state key cart.items, and the rest of
the path travels alongside as metadata. Modelling it the other way — a node
per observed path — would invent entities the application never declared.
Parameters:
- Source:
Returns:
The declaration reached, the remaining path, how much to trust it, and the reason nothing was reached when nothing was.
- Type
- Object
(static) scanReferences(code, optionsopt) → {Object}
Scans expression source for member chains and what is done to them.
Parameters:
| Name | Type | Attributes | Description | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
code |
string | The expression or action body. |
|||||||||||||
options |
object |
<optional> |
Scan options. Properties
|
- Source:
Returns:
Every chain found, the local bindings, destructuring aliases and syntactic observations worth reporting (a spread, for instance).
- Type
- Object
(static) skipLiteral(code, i) → {Object}
Advances past a string, template literal or comment starting at i.
Returns i unchanged when nothing at that position opens one, which lets
the callers use it as an unconditional first step in their loops.
Parameters:
| Name | Type | Description |
|---|---|---|
code |
string | The source. |
i |
number | Start offset. |
- Source:
Returns:
Where the construct ends, plus any ${...} bodies found inside a template
literal so the caller can scan them too.
- Type
- Object
(inner) isIdentPart(ch) → {boolean}
Whether a character can continue an identifier.
Parameters:
| Name | Type | Description |
|---|---|---|
ch |
string | A single character. |
- Source:
Returns:
True when the character may continue an identifier.
- Type
- boolean
(inner) isIdentStart(ch) → {boolean}
Whether a character can start an identifier.
Parameters:
| Name | Type | Description |
|---|---|---|
ch |
string | A single character. |
- Source:
Returns:
True when the character may begin an identifier.
- Type
- boolean
(inner) isNumericIndex(inner) → {boolean}
Whether a computed member is a literal element index.
items[0] is fully determined, so it becomes an [] path segment without
being reported as unresolved: Atlas models declared symbols and does not
model individual elements, and there is nothing here it failed to follow.
Parameters:
| Name | Type | Description |
|---|---|---|
inner |
string | The text between the brackets. |
- Source:
Returns:
True for a numeric literal index.
- Type
- boolean
(inner) matchBracket(code, open) → {number}
Finds the offset of the bracket closing the one at open.
Parameters:
| Name | Type | Description |
|---|---|---|
code |
string | The source. |
open |
number | Offset of the opening bracket. |
- Source:
Returns:
Offset of the matching close, or -1 when unbalanced.
- Type
- number
(inner) readChain(code, i) → {object}
Reads a member chain that begins at i.
Parameters:
| Name | Type | Description |
|---|---|---|
code |
string | The source. |
i |
number | Offset of the root identifier. |
- Source:
Returns:
The chain: root, segments, flags, extent and any nested expressions found inside computed members.
- Type
- object
(inner) readUsage(code, end) → {Object|null}
Detects an assignment or update immediately following a chain.
Parameters:
| Name | Type | Description |
|---|---|---|
code |
string | The source. |
end |
number | Offset just past the chain. |
- Source:
Returns:
What was done to the chain.
- Type
- Object | null
(inner) skipSpace(code, i) → {number}
Advances past whitespace.
Parameters:
| Name | Type | Description |
|---|---|---|
code |
string | The source. |
i |
number | Start offset. |
- Source:
Returns:
The first non-whitespace offset at or after i.
- Type
- number
(inner) staticKey(inner) → {string|null}
Reads a computed member key when it is a literal.
items['qty'] names a member as precisely as items.qty does, so it should
not be downgraded to a dynamic access. A numeric index is an element, not a
member, and is normalised to [] alongside genuinely computed keys.
Parameters:
| Name | Type | Description |
|---|---|---|
inner |
string | The text between the brackets. |
- Source:
Returns:
The member name, or null when the key is not a literal.
- Type
- string | null