Module: lib/compiler/atlas/resolve

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:

  1. collectLocals finds every name the body binds itself — const, let, var, function and arrow parameters, catch bindings, destructuring patterns. It runs first so that a reference appearing ahead of the declaration that shadows it is still recognised as local.
  2. 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:
  • Set:.<string:>
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:
  • Set:.<string:>
Source:

(static, constant) COLLECTION_METHODS :Set:.<string:>

Collection methods that yield another collection of the same elements.

Type:
  • Set:.<string:>
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:
  • Set:.<string:>
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:
  • Set:.<string:>
Source:

(inner, constant) ASSIGN_OPERATORS :Array:.<string:>

Assignment operators, longest first so ??= is matched before ?.

Type:
  • Array:.<string:>
Source:

(inner, constant) DECLARATION_KEYWORDS :Set:.<string:>

Statements that begin a binding.

Type:
  • Set:.<string:>
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.

Type
Set:.<string:>

(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:
Name Type Description
ref object

A reference from scanReferences.

scope object

The resolution scope.

Properties
Name Type Attributes Description
ownerId string

The owning node's id.

ownerKind string

component, page or bridge.

state Set:.<string:> <optional>

Declared state keys.

computed Set:.<string:> <optional>

Declared computed names.

actions Set:.<string:> <optional>

Declared action names.

resources Set:.<string:> <optional>

Declared resource names.

bridges Map:.<string:, object:> <optional>

Imported bridges by local name.

loopVars Map:.<string:, object:> <optional>

Loop variables by name.

slotProps Set:.<string:> <optional>

Scoped-slot variable names.

locals Set:.<string:> <optional>

Locally bound names.

selfBridge object <optional>

The bridge descriptor when resolving inside one.

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
Name Type Attributes Description
locals Set:.<string:> <optional>

Names bound locally; computed when omitted.

base number <optional>

Offset of code within its containing file.

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