Skip to content

v0.9.34 - #317

Merged
alaa-eddine merged 27 commits into
mainfrom
dev
Sep 17, 2026
Merged

alaa-eddine merged 27 commits into
mainfrom
dev

Conversation

@alaa-eddine

Copy link
Copy Markdown
Collaborator

No description provided.

alexgrover and others added 27 commits September 1, 2026 19:58
…t undefined as na in array element validation and return the NaN na sentinel from from_gradient

Co-authored-by: Cursor <cursoragent@cursor.com>
Both were listed as implemented in docs/api-coverage but did not exist,
so any script calling them failed with 'ta.max is not a function'.

- Incremental O(1) per bar with committed/tentative state keyed by
  context.idx so live-bar re-evaluation does not corrupt history
- na until the first non-na source value; later na values are ignored
- Per-call-site state via _callId
- Regenerated ta.index.ts barrel
- Tests use hand-derived step series and an independent JS running
  max/min over close as the reference

Co-authored-by: Cursor <cursoragent@cursor.com>
- Point the CLA bot at a new signatures file so contributors accept the
  updated CLA on their next PR; CONTRIBUTING link updated.
- Regression fixtures: replace two third-party indicator ports with
  LuxAlgo Library indicators (Squeeze Index, Bollinger Bands Breakout
  Oscillator); regenerate baselines; add a weekly regression test.
- Simplify math.round precision handling and parser layout-token
  skipping; refresh related tests.
Fix na colors from color.from_gradient crashing array mutators
Add ta.max and ta.min (trailing maximum / minimum)
…eanup

chore: CLA v2 re-sign, regression fixture refresh, small cleanups
…imes

Pine Script treats `_` as a write-only discard identifier that may be
declared any number of times, in any scope, including several times in
the same scope (TradingView docs, "Using an underscore (_) as an
identifier"). JavaScript forbids re-declaring a let/var binding in one
scope, so scripts such as

    [_, s1, _] = ta.macd(close, 12, 26, 9)
    [_, s2, _] = ta.macd(close, 5, 10, 3)
    _ = ta.sma(close, 10)

failed with `SyntaxError: Identifier '_' has already been declared`.

The codegen previously only de-duplicated `_` *within* a single tuple.
It now renames every `_` declaration target (plain declarations, tuple
declarations and `for [..] in` headers) to a fresh `_$N` placeholder.
`$` is not a legal Pine identifier character, so the placeholders cannot
collide with user variables.

Adds tests/transpiler/underscore-discard-identifier.test.ts as a
regression guard; expected values come from the same computations
written with uniquely-named variables.

Co-authored-by: Cursor <cursoragent@cursor.com>
TradingView rejects any read of `_` (Undeclared identifier). PineTS surfaces every undeclared identifier as a runtime ReferenceError; these tests pin that `_` behaves the same and never silently resolves to a discarded value.

Co-authored-by: Cursor <cursoragent@cursor.com>
The `scale` and `settlement_as_close` enums exist in namespaces/Types.ts and
are spread into the context, but were missing from CONTEXT_PINE_VARS, so the
transpiler never bound them and any `scale.*` reference threw
"scale is not defined" (e.g. `indicator("x", scale = scale.right)`).

Also add both to NAMESPACE_COLLISION_NAMES: scripts commonly declare a
variable named `scale` next to `indicator(scale = scale.left)`, which
TradingView allows.

Found in 12 of 729 popular open-source TradingView indicators.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ew text_formatting

label.set_text_font_family() and label.set_text_formatting() could not be
called from scripts: LabelHelper had no namespace-level setters and Context
did not bind them, so scripts threw "label.set_text_font_family is not a
function". label.new() also ignored the v6 `text_formatting` argument.

Mirrors the existing box implementation: setters on LabelHelper bound in
Context, `text_formatting` stored on LabelObject (constructor, copy() and plot
data), and the LabelObject method-call delegates now route through the helper.
API coverage docs updated.

Found in 7 of 729 popular open-source TradingView indicators; 5 of them run
without errors with this change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
table.cell_set_text_formatting() was not implemented or bound in Context, so
scripts calling it threw "table.cell_set_text_formatting is not a function",
and table.cell() ignored the v6 `text_formatting` argument.

Mirrors cell_set_text_font_family: `text_formatting` is parsed in table.cell()
(positional index 13 and named), stored on the cell (default "none", matching
text.format_none), settable through the helper and the table object
delegate, and bound in Context. API coverage docs updated.

Found in 1 of 729 popular open-source TradingView indicators (Parabolic SAR
Constraint Kinematics & Run Geometry), which runs without errors with this
change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pine's `display.*` values form a set type: `+` unions two displays and `-`
removes one's surfaces from the other (`display.all - display.price_scale`).
The runtime keeps them as member-name strings, so native `-` yielded NaN and
`+` a raw concatenation in source order (`display.all + display.none` →
'allnone').

A post-process pass, `transformDisplayArithmetic`, routes `+` / `-` with a
`display.*` operand — literal members, chained expressions, or a variable
combined with a member — to `display.__union` / `display.__minus`, which
compute the set and report it as the canonical concatenation of member names
(pane, data_window, status_line, price_scale; 'all' / 'none' for the full /
empty set), the shape hosts already parse. `display.all - display.none` →
'all', `display.none - display.all` → 'none', `display.pane + display.pane` →
'pane'. Plain member values and the enum are unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
Pine allows a script to declare a function whose name matches a constant
namespace (`position(x) => close + x`) and to keep using that namespace's
members in the same script. Two transpiler passes broke this:

- The pineToJS codegen collision pass renamed the declaration to
  `position_$N` but left bare call sites alone (it assumed a bare callee is
  always the built-in, which is only true for VARIABLE collisions such as
  `fill = 3` alongside `fill(p1, p2)`), so `plot(position(14))` resolved to
  the constants object -> `TypeError: position is not a function`. The pass
  now records which collision names were declared as functions and renames
  their bare callees too.

- The parser's `name -> name_var` rewrite (for a variable sharing a user
  function's name) fired on the namespace base of `position.top_right` once
  a `position()` function existed -> `ReferenceError: position_var is not
  defined`. It now skips a collision-name identifier followed by `.`.

Affects every entry of NAMESPACE_COLLISION_NAMES and makes adding names to
that list (e.g. `scale`, #305) safe for scripts that use them as functions.

Tests: tests/transpiler/namespace-identifier-collision.test.ts (7 new cases:
bare call, member-access coexistence, argument position, nested/indirect
calls, variable-collision guard, `scale` forward guard).

Co-authored-by: Cursor <cursoragent@cursor.com>
Add label.set_text_font_family, label.set_text_formatting and label.new text_formatting
Add table.cell_set_text_formatting and table.cell text_formatting
fix(transpiler): + / - on display constants are set operations
UDT field defaults declared as `float x = na` stored the runtime NAHelper
object in the field instead of NaN. `na(obj.x)` masked it (NAHelper.any
special-cases the helper), but `nz(obj.x, v)` returned the helper untouched,
and pushing that into a typed array threw:

  Cannot call 'array.unshift' with argument 'value'='[object Object]'.
  An argument of 'literal object' type was used but a 'float' is expected.

Series.from() only unwrapped helpers whose `__value` is a Series (time,
time_close). NAHelper's `__value` is a scalar NaN, so it fell through and was
wrapped as an opaque object. Resolve scalar `__value` helpers at this common
unwrap point so UDT defaults, nz(), math.* and every other consumer see a
real NaN.

Adds a regression test to tests/core/udt-field-defaults.test.ts.

Co-authored-by: Cursor <cursoragent@cursor.com>
fix(runtime): resolve the `na` helper to NaN in Series.from() (UDT `= na` defaults)
fix(transpiler): user-defined functions named after a constant namespace
…tion

fix(pineToJS): allow the `_` discard identifier to be declared multiple times
Fix scale and settlement_as_close namespaces not resolving in scripts
@alaa-eddine
alaa-eddine merged commit beacd58 into main Sep 17, 2026
1 check passed
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 17, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants