Skip to content

Latest commit

 

History

History
244 lines (186 loc) · 8.1 KB

API.md

File metadata and controls

244 lines (186 loc) · 8.1 KB

API Reference

All exports from @opus-aether-ai/pine-transpiler. For a high-level walkthrough see the README; for internal architecture see ARCHITECTURE.md.

Table of contents


Top-level functions

transpileToPineJS

Transpile Pine Script to a chart-host CustomIndicator factory. The indicator runtime is compiled with new Function(...) when the factory is instantiated. Use this for local development or any environment where unsafe-eval is allowed (most chart hosts).

function transpileToPineJS(
  code: string,                    // Pine Script source
  indicatorId: string,             // Stable unique identifier
  indicatorName?: string,          // Display name shown in the chart UI
  options?: TranspileOptions,      // Optional flags
): TranspileToPineJSResult;

interface TranspileToPineJSResult {
  success: boolean;
  indicatorFactory?: IndicatorFactory;
  error?: string;
}

interface TranspileOptions {
  /**
   * When `true`, emit a `bg_colorer` plot synthesized from
   * `box.new(..., bgcolor=...)` patterns so renderer-less consumers
   * get session-highlight bands directly from the transpiler.
   *
   * Default `false` — host renderers consuming `__visualEvents` draw
   * proper price-constrained rectangles, and bg_colorer bands would
   * conflict. See HOST_RENDERING_CONTRACT.md.
   */
  autoBgColorerForBoxes?: boolean;
}

transpileToStandaloneFactory

Same input as transpileToPineJS, but the result is an ESM module source string exporting a createIndicator(PineJS) function. You serialize this to disk at build time and import it at runtime — no new Function(...) is involved on the chart host, satisfying strict-CSP deployments.

function transpileToStandaloneFactory(
  code: string,
  indicatorId: string,
  indicatorName?: string,
  options?: TranspileOptions,
): TranspileToStandaloneFactoryResult;

interface TranspileToStandaloneFactoryResult {
  success: boolean;
  factoryCode?: string;            // ESM source you can write to a .js file
  error?: string;
}

See Strict-CSP integration below for the full pattern.

transpile

Low-level escape hatch that returns the raw JavaScript body string only — no factory wrapper, no metainfo. Useful for inspection, custom code-generation backends, or tooling that wants to insert the output into a different runtime shell.

function transpile(code: string): string;

canTranspilePineScript

Lex + parse the source and return whether the input is structurally valid Pine. Does not execute. Cheap pre-check for editors / form validation.

function canTranspilePineScript(code: string): {
  valid: boolean;
  reason?: string;
};

executePineJS

Execute native PineJS JavaScript source (not Pine Script) and wrap the result in the standard IndicatorFactory shape. Lets you slot a hand-written createIndicator next to transpiled ones through a single registration path.

function executePineJS(
  code: string,
  indicatorId: string,
  indicatorName?: string,
): TranspileToPineJSResult;

Pipeline API (advanced)

transpileToPineJS and transpileToStandaloneFactory are thin wrappers around a four-stage pipeline. The stages are individually exported so tools (LSPs, linters, custom backends, fuzzers) can compose them without re-wiring the sequence.

import {
  parse,              // (code) => Program (AST)
  extractMetadata,    // (ast) => MetadataVisitor (name, inputs, plots, ...)
  generateBody,       // (ast, historicalAccess, helperUsage?) => string
  buildFactory,       // (metadata, body, opts) => IndicatorFactory
  compile,            // one-shot: (code, opts) => everything below
  validateInputSize,  // (code) => void — throws if >1 MB
  HelperUsage,        // tracker of which runtime-helper categories the body emits
  MAX_INPUT_SIZE,     // 1_000_000
} from '@opus-aether-ai/pine-transpiler';

// Inspect just the AST:
const ast = parse(source);

// Or run the full pipeline and inspect intermediate stages:
const { metadata, mainBody, helperUsage, factory } =
  compile(source, { indicatorId: 'demo' });

HelperUsage

The generator marks runtime-helper categories as it emits each Pine builtin call. The factory builder reads this (IndicatorFactoryOptions.helperUsage) to decide which helper libraries to inject into the preamble. Categories tracked: math, session, stdplus, array, map, matrix, color, string, utility, state.

This replaced an earlier string-grep over the generated body. If you build your own factory wrapper around generateBody, pass the same HelperUsage instance so the preamble matches the body's needs.


Test harness sub-export

import {
  runChartRuntimeHarness,
  type ChartRuntimeHarnessOptions,
  type ChartRuntimeHarnessReport,
} from '@opus-aether-ai/pine-transpiler/test-harness';

const report = runChartRuntimeHarness({
  fixtureName: 'ict-killzones.pine',
  source: pineSource,
  bars: 300,
  barIndexStart: 10_000,
});

if (!report.pass) {
  console.error(report);
}

Use this when you want to catch chart-host breakages before webapp integration — non-constructable constructors, missing metainfo.styles[plot.id], undefined plot slots, reducer crashes against host-runtime-shaped reducer paths.


Mapping introspection

For tooling that needs to know what Pine functions the transpiler covers:

import {
  TA_FUNCTION_MAPPINGS,
  MATH_FUNCTION_MAPPINGS,
  TIME_FUNCTION_MAPPINGS,
  MULTI_OUTPUT_MAPPINGS,
  getMappingStats,
  getAllPineFunctionNames,
} from '@opus-aether-ai/pine-transpiler';

const stats = getMappingStats();
// { ta: 50, math: 19, time: 8, multiOutput: 6, ... }

const all = getAllPineFunctionNames();
// ['ta.sma', 'ta.ema', 'math.abs', ...]

Constants and types

import {
  COLOR_MAP,         // Pine color.* constant → hex resolution
  PRICE_SOURCES,     // ['open','high','low','close','volume','hl2','hlc3','ohlc4']
  MAX_INPUT_SIZE,    // 1_000_000 — hard cap on input size in characters
} from '@opus-aether-ai/pine-transpiler';

import type {
  IndicatorFactory,
  ParsedIndicator,
  ParsedInput,
  ParsedPlot,
  ParsedVariable,
  ParsedFunction,
  TAFunctionMapping,
  MultiOutputFunctionMapping,
  ComparisonFunctionMapping,
  TimeFunctionMapping,
  TranspilerRuntimeError,
  TranspileToPineJSResult,
  TranspileToStandaloneFactoryResult,
} from '@opus-aether-ai/pine-transpiler';

Strict-CSP integration

When the chart host runs under a Content Security Policy that forbids unsafe-eval, new Function(...) is blocked — so transpileToPineJS will fail at indicator-construction time. Use transpileToStandaloneFactory instead and ship the result as a built module:

// scripts/build-indicator.ts (Node, build-time)
import { writeFileSync } from 'node:fs';
import { transpileToStandaloneFactory } from '@opus-aether-ai/pine-transpiler';

const built = transpileToStandaloneFactory(
  pineSource,
  'ict_killzones',
  'ICT Killzones',
);
if (!built.success) throw new Error(built.error);

writeFileSync('generated/ict-killzones.factory.js', built.factoryCode!);
// app code (browser, runtime)
import { createIndicator } from './generated/ict-killzones.factory.js';

const indicator = createIndicator(PineJS);
// register through custom_indicators_getter as usual

The emitted ESM module is self-contained — it doesn't import from @opus-aether-ai/pine-transpiler at runtime, so end users don't need the package installed in their CSP-restricted environment.