@wiredwp/robinpath
Advanced tools
| import { Environment } from '../types/Environment.type'; | ||
| import { Statement, Arg } from '../types/Ast.type'; | ||
| import { Value } from '../utils'; | ||
| export declare class ASTSerializer { | ||
| private environment; | ||
| constructor(environment: Environment); | ||
| /** | ||
| * Find the module name for a given function name | ||
| * Returns the module name if found, null otherwise | ||
| */ | ||
| findModuleName(functionName: string, currentModuleContext?: string | null): string | null; | ||
| /** | ||
| * Get a simplified tree structure of the AST for navigation | ||
| */ | ||
| getStructure(statements: Statement[], nodeKeyPrefix?: string): any[]; | ||
| /** | ||
| * Generate a human-readable label for a statement | ||
| */ | ||
| private getNodeLabel; | ||
| /** | ||
| * Serialize a statement to a JSON-serializable object | ||
| * @param stmt The statement to serialize | ||
| * @param currentModuleContext Optional module context from "use" command | ||
| * @param lastValue Optional last value (execution state) - can be a Value or a state object with lastValue and beforeValue | ||
| * @param nodeKey Optional key for the node | ||
| */ | ||
| serializeStatement(stmt: Statement, currentModuleContext?: string | null, lastValue?: Value | { | ||
| lastValue: Value; | ||
| beforeValue: Value; | ||
| } | null, nodeKey?: string): any; | ||
| /** | ||
| * Serialize an argument to a JSON-serializable object | ||
| */ | ||
| serializeArg(arg: Arg, currentModuleContext?: string | null, nodeKey?: string): any; | ||
| } |
| import { TokenStream } from '../classes/TokenStream'; | ||
| import { CellBlock } from '../types/Ast.type'; | ||
| /** | ||
| * Parse a cell block from the current position | ||
| * | ||
| * @param stream - Token stream positioned at the cell open fence | ||
| * @param source - Full source code string | ||
| * @param parseStatement - Function to parse statements (for code cells) | ||
| * @returns CellBlock if parsed, null otherwise | ||
| */ | ||
| export declare function parseCellBlock(stream: TokenStream, source: string, _parseStatement: (stream: TokenStream) => any): Promise<CellBlock | null>; |
| import { TokenStream } from '../classes/TokenStream'; | ||
| import { ChunkMarkerStatement } from '../types/Ast.type'; | ||
| /** | ||
| * Parse a chunk marker from the current line | ||
| * | ||
| * Syntax: --- chunk:<id> [key:value ...] --- | ||
| * | ||
| * @param stream - Token stream positioned at the start of a potential chunk marker | ||
| * @param source - Full source code string for extracting raw line | ||
| * @returns ChunkMarkerStatement if parsed, null otherwise | ||
| */ | ||
| export declare function parseChunkMarker(stream: TokenStream, source: string): ChunkMarkerStatement | null; |
| /** | ||
| * Fence Classifier - Classifies fence lines with priority order | ||
| * | ||
| * Priority order (to avoid ambiguity): | ||
| * 1. ---cell ...--- (cell open) | ||
| * 2. ---end--- (cell close) | ||
| * 3. --- chunk:... --- (chunk marker) | ||
| * 4. bare --- (prompt fence open/close) | ||
| */ | ||
| export type FenceClassification = { | ||
| kind: 'cell_open'; | ||
| cellType: string; | ||
| meta: Record<string, string>; | ||
| } | { | ||
| kind: 'cell_end'; | ||
| } | { | ||
| kind: 'chunk_marker'; | ||
| id: string; | ||
| meta: Record<string, string>; | ||
| } | { | ||
| kind: 'prompt_fence'; | ||
| } | null; | ||
| /** | ||
| * Classify a fence line according to priority order | ||
| * | ||
| * @param line - Raw line string to classify | ||
| * @returns Classification result or null if not a fence line | ||
| */ | ||
| export declare function classifyFenceLine(line: string): FenceClassification; |
| import { Token } from '../classes/Lexer'; | ||
| import { CodePosition } from '../types/Ast.type'; | ||
| import { TokenStream } from '../classes/TokenStream'; | ||
| /** | ||
| * Create CodePosition from start and end tokens | ||
| * @param startToken - The token where the node starts | ||
| * @param endToken - The token where the node ends | ||
| * @returns 0-indexed CodePosition | ||
| */ | ||
| export declare function createCodePosition(startToken: Token, endToken: Token): CodePosition; | ||
| /** | ||
| * Skip whitespace and comments on the current line | ||
| * @param stream - TokenStream to skip in | ||
| */ | ||
| export declare function skipWhitespaceOnLine(stream: TokenStream): void; |
| import { TokenStream } from '../classes/TokenStream'; | ||
| import { PromptBlockStatement } from '../types/Ast.type'; | ||
| /** | ||
| * Parse a prompt block from the current position | ||
| * | ||
| * @param stream - Token stream positioned at the opening prompt fence | ||
| * @param source - Full source code string | ||
| * @returns PromptBlockStatement if parsed, null otherwise | ||
| */ | ||
| export declare function parsePromptBlock(stream: TokenStream, source: string): PromptBlockStatement | null; |
| import { Value } from '../utils'; | ||
| import { DefineFunction, OnBlock, Arg } from './Ast.type'; | ||
| export type BuiltinCallback = (callbackArgs: Value[]) => Promise<Value> | Value | null; | ||
| export type BuiltinHandler = (args: Value[], callback?: BuiltinCallback | null) => Promise<Value> | Value | null; | ||
| export type DecoratorHandler = (targetName: string, func: DefineFunction | null, originalArgs: Value[], decoratorArgs: Value[], originalDecoratorArgs?: Arg[]) => Promise<Value[] | Value | null | undefined>; | ||
| export type ParseDecoratorHandler = (targetName: string, func: DefineFunction | null, decoratorArgs: Arg[], environment: Environment) => Promise<void> | void; | ||
| export interface Environment { | ||
| variables: Map<string, Value>; | ||
| functions: Map<string, DefineFunction>; | ||
| builtins: Map<string, BuiltinHandler>; | ||
| decorators: Map<string, DecoratorHandler>; | ||
| parseDecorators: Map<string, ParseDecoratorHandler>; | ||
| metadata: Map<string, FunctionMetadata>; | ||
| moduleMetadata: Map<string, ModuleMetadata>; | ||
| currentModule: string | null; | ||
| variableMetadata: Map<string, Map<string, Value>>; | ||
| functionMetadata: Map<string, Map<string, Value>>; | ||
| constants: Set<string>; | ||
| eventHandlers: Map<string, OnBlock[]>; | ||
| } | ||
| export interface Frame { | ||
| locals: Map<string, Value>; | ||
| lastValue: Value; | ||
| isFunctionFrame?: boolean; | ||
| forgotten?: Set<string>; | ||
| isIsolatedScope?: boolean; | ||
| } | ||
| export type DataType = 'string' | 'number' | 'boolean' | 'object' | 'array' | 'null' | 'any'; | ||
| export type FormInputType = 'text' | 'number' | 'textarea' | 'select' | 'checkbox' | 'radio' | 'date' | 'datetime' | 'file' | 'json' | 'code' | 'varname'; | ||
| export interface ParameterMetadata { | ||
| name: string; | ||
| label?: string; | ||
| dataType: DataType; | ||
| description: string; | ||
| formInputType: FormInputType; | ||
| required?: boolean; | ||
| defaultValue?: Value; | ||
| children?: ParameterMetadata; | ||
| } | ||
| export interface FunctionMetadata { | ||
| description: string; | ||
| parameters: ParameterMetadata[]; | ||
| returnType: DataType; | ||
| returnDescription: string; | ||
| example?: string; | ||
| } | ||
| export interface ModuleMetadata { | ||
| description: string; | ||
| methods: string[]; | ||
| author?: string; | ||
| category?: string; | ||
| doc_url?: string; | ||
| } |
@@ -1,4 +0,163 @@ | ||
| import { Statement } from '../../types/Ast.type'; | ||
| import { Statement, CommentWithPosition } from '../../types/Ast.type'; | ||
| import { Writer } from './Writer'; | ||
| import { LineIndex } from './LineIndex'; | ||
| import { Patch, CommentLayout, PrintContext } from './types'; | ||
| export type { CommentWithPosition, LineIndex, PrintContext }; | ||
| export { Writer }; | ||
| /** | ||
| * CommentLayout - Normalize comment ownership | ||
| * | ||
| * Decides, per statement: | ||
| * - leadingComments: Comment[] (non-inline) | ||
| * - inlineComment: Comment | null | ||
| * - leadingGapLines: number (blank lines between last leading comment and statement) | ||
| * - trailingBlankLinesAfterStandaloneComment: number (only for standalone comment nodes) | ||
| */ | ||
| export declare class CommentLayoutNormalizer { | ||
| /** | ||
| * Normalize comment layout for a statement | ||
| */ | ||
| static normalize(node: Statement, lineIndex: LineIndex): CommentLayout; | ||
| } | ||
| /** | ||
| * PatchApplier - Apply patches to source code | ||
| * | ||
| * Sort patches descending (as you do now) and apply. | ||
| * Optional: validate overlaps and throw in dev mode. | ||
| */ | ||
| export declare class PatchApplier { | ||
| /** | ||
| * Apply patches to source code | ||
| * Patches are sorted descending by startOffset and applied from end to start | ||
| * to prevent character position shifts from affecting subsequent replacements | ||
| */ | ||
| static apply(originalScript: string, patches: Patch[]): string; | ||
| /** | ||
| * Validate that patches don't overlap | ||
| * @internal This method is kept for potential future use or manual invocation | ||
| */ | ||
| static validatePatches(patches: Patch[]): void; | ||
| } | ||
| /** | ||
| * PatchPlanner - Collect edit operations | ||
| * | ||
| * Produces Patch[] = { startOffset, endOffset, replacement }. | ||
| * Responsible for "range selection" (including blank lines, inline comment removal, etc.) | ||
| * Must guarantee patches don't overlap (or resolve overlaps deterministically). | ||
| */ | ||
| export declare class PatchPlanner { | ||
| private lineIndex; | ||
| private patches; | ||
| private originalScript; | ||
| private originalAST; | ||
| /** | ||
| * Enable defensive validation of extracted code. | ||
| * When true, extracted code is validated before use and falls back to regeneration if invalid. | ||
| * Set via ROBINPATH_DEBUG environment variable or constructor option. | ||
| */ | ||
| private debugMode; | ||
| constructor(originalScript: string, options?: { | ||
| debugMode?: boolean; | ||
| }); | ||
| /** | ||
| * Plan patches for all nodes in the AST | ||
| * This includes patches for: | ||
| * - Updated nodes (in modified AST) | ||
| * - New nodes (in modified AST but not in original) | ||
| * - Deleted nodes (in original AST but not in modified) | ||
| */ | ||
| planPatches(ast: Statement[]): Promise<Patch[]>; | ||
| /** | ||
| * Plan a patch for a deleted node | ||
| */ | ||
| private planPatchForDeletedNode; | ||
| /** | ||
| * Plan a patch for a single node | ||
| */ | ||
| private planPatchForNode; | ||
| /** | ||
| * Plan a patch for a new node (insertion) | ||
| */ | ||
| private planPatchForNewNode; | ||
| /** | ||
| * Plan patch for leading comments (non-overlapping case) | ||
| */ | ||
| private planPatchForLeadingComments; | ||
| /** | ||
| * Generate replacement without leading comments (for non-overlapping case) | ||
| */ | ||
| private generateReplacementWithoutLeadingComments; | ||
| /** | ||
| * Plan patch for a standalone comment node | ||
| */ | ||
| private planPatchForCommentNode; | ||
| /** | ||
| * Find the stop row for comment blank line inclusion | ||
| */ | ||
| private findStopRowForComment; | ||
| /** | ||
| * Plan patch to remove existing comments | ||
| */ | ||
| private planPatchToRemoveComments; | ||
| /** | ||
| * Compute the range for a statement region | ||
| */ | ||
| private computeStatementRange; | ||
| /** | ||
| * Generate replacement text for a node | ||
| */ | ||
| private generateReplacement; | ||
| /** | ||
| * Preserve blank lines that were included in the range after the statement | ||
| */ | ||
| private preserveBlankLinesInRange; | ||
| /** | ||
| * Extract original code from the script if the node hasn't changed | ||
| * Returns null if the node has changed and needs regeneration | ||
| * | ||
| * This preserves all original formatting including: | ||
| * - Indentation (spaces and tabs) | ||
| * - Spacing within statements | ||
| * - Blank lines | ||
| */ | ||
| private extractOriginalCode; | ||
| /** | ||
| * Validate extracted code by checking if it parses correctly and matches expected type. | ||
| * Used in debug mode to detect extraction corruption. | ||
| */ | ||
| private validateExtractedCode; | ||
| /** | ||
| * Find the original node that corresponds to the modified node | ||
| */ | ||
| private findOriginalNode; | ||
| /** | ||
| * Compare two nodes to see if they're equal (ignoring codePos and metadata) | ||
| */ | ||
| private nodesAreEqual; | ||
| /** | ||
| * Generate code with preserved indentation and spacing from original | ||
| * This is used when we must regenerate code but want to preserve formatting | ||
| */ | ||
| private generateCodeWithPreservedIndentation; | ||
| } | ||
| /** | ||
| * ASTToCodeConverter - Converts AST nodes back to source code | ||
| * | ||
| * This class handles the conversion of AST (Abstract Syntax Tree) nodes | ||
| * back into RobinPath source code strings. It provides methods for: | ||
| * - Updating source code based on AST changes | ||
| * - Reconstructing code from individual AST nodes | ||
| * - Handling comments, indentation, and code positioning | ||
| */ | ||
| export declare class ASTToCodeConverter { | ||
| /** | ||
| * Validate that AST node positions are within bounds of the source code. | ||
| * This helps detect stale AST data from external source modifications. | ||
| * | ||
| * @param source The current source code | ||
| * @param ast The AST to validate | ||
| * @returns Object with isValid flag and optional error details | ||
| */ | ||
| private validateASTPositions; | ||
| /** | ||
| * Update source code based on AST changes | ||
@@ -11,3 +170,3 @@ * Uses precise character-level positions (codePos.startRow/startCol/endRow/endCol) to update code | ||
| */ | ||
| updateCodeFromAST(originalScript: string, ast: Statement[]): string; | ||
| updateCodeFromAST(originalScript: string, ast: Statement[]): Promise<string>; | ||
| /** | ||
@@ -14,0 +173,0 @@ * Reconstruct code string from an AST node |
| /** | ||
| * Code Converter Module - Exports | ||
| */ | ||
| export { ASTToCodeConverter } from './ASTToCodeConverter'; | ||
| export { ASTToCodeConverter, PatchPlanner, PatchApplier, CommentLayoutNormalizer } from './ASTToCodeConverter'; | ||
| export { Writer } from './Writer'; | ||
| export { LineIndexImpl } from './LineIndex'; | ||
| export { Writer } from './Writer'; | ||
| export { Printer } from './Printer'; | ||
| export { PatchPlanner } from './PatchPlanner'; | ||
| export { PatchApplier } from './PatchApplier'; | ||
| export { CommentLayoutNormalizer } from './CommentLayout'; | ||
| export type { Patch, CommentLayout, PrintContext, LineIndex } from './types'; | ||
| export type { Patch, CommentLayout, PrintContext, LineIndex, CommentWithPosition } from './types'; |
@@ -1,2 +0,21 @@ | ||
| import { LineIndex } from './types'; | ||
| /** | ||
| * LineIndex - Fast row/col → offset conversion | ||
| */ | ||
| /** | ||
| * LineIndex interface for fast row/col → offset conversion | ||
| */ | ||
| export interface LineIndex { | ||
| offsetAt(row: number, col: number, exclusive?: boolean): number; | ||
| lineEndOffset(row: number): number; | ||
| hasNewline(row: number): boolean; | ||
| getLine(row: number): string; | ||
| getLines(): string[]; | ||
| lineCount(): number; | ||
| } | ||
| /** | ||
| * LineIndex implementation - Fast row/col → offset conversion | ||
| * | ||
| * Build once per originalScript. Provides O(1) offset conversion | ||
| * by pre-computing line-start offsets. | ||
| */ | ||
| export declare class LineIndexImpl implements LineIndex { | ||
@@ -3,0 +22,0 @@ private readonly lineStartOffsets; |
@@ -1,5 +0,13 @@ | ||
| import { Statement, CommentWithPosition } from '../../types/Ast.type'; | ||
| import { PrintContext, CommentWithPosition } from './types'; | ||
| import { Value } from '../../utils/types'; | ||
| import { PrintContext } from './types'; | ||
| import { Statement } from '../../types/Ast.type'; | ||
| import { Writer } from './Writer'; | ||
| /** | ||
| * Printer class - AST → string conversion | ||
| * | ||
| * Pure function(s), no access to originalScript. | ||
| * Uses a Writer to avoid heavy string concatenations. | ||
| */ | ||
| export declare class Printer { | ||
| private static printersRegistry; | ||
| /** | ||
@@ -14,6 +22,2 @@ * Print a statement node to code | ||
| /** | ||
| * Print an argument | ||
| */ | ||
| static printArg(arg: any, ctx: PrintContext): string | null; | ||
| /** | ||
| * Get value type | ||
@@ -26,2 +30,90 @@ */ | ||
| static convertValueType(value: Value, targetType: 'string' | 'number' | 'boolean' | 'null' | 'object' | 'array'): Value | null; | ||
| /** | ||
| * Print argument/expression code | ||
| */ | ||
| static printArg(arg: any, _ctx: PrintContext): string | null; | ||
| /** | ||
| * Print a variable reference | ||
| */ | ||
| static printVarRef(name: string, path?: any[]): string; | ||
| /** | ||
| * Print an into target | ||
| */ | ||
| static printIntoTarget(targetName: string, targetPath?: any[]): string; | ||
| /** | ||
| * Print assignment node | ||
| */ | ||
| static printAssignment(node: any, writer: Writer, ctx: PrintContext): void; | ||
| /** | ||
| * Print cell block node | ||
| */ | ||
| static printCellBlock(node: any, writer: Writer, ctx: PrintContext): void; | ||
| /** | ||
| * Print chunk marker node | ||
| */ | ||
| static printChunkMarker(node: any, writer: Writer, _ctx: PrintContext): void; | ||
| /** | ||
| * Print command node | ||
| */ | ||
| static printCommand(node: any, writer: Writer, ctx: PrintContext): void; | ||
| /** | ||
| * Print a comment node | ||
| */ | ||
| static printCommentNode(node: any, writer: Writer, _ctx: PrintContext): void; | ||
| /** | ||
| * Get leading comments from a statement node. | ||
| */ | ||
| private static getLeadingComments; | ||
| /** | ||
| * Get inline comment from a statement node. | ||
| */ | ||
| static getInlineComment(stmt: any): CommentWithPosition | null; | ||
| /** | ||
| * Format an inline comment as a string to append to a line. | ||
| */ | ||
| static formatInlineComment(comment: CommentWithPosition | null): string; | ||
| /** | ||
| * Emit decorators for a node if they exist. | ||
| */ | ||
| private static emitDecorators; | ||
| /** | ||
| * Emit leading comments for a statement, preserving blank lines between them. | ||
| */ | ||
| static emitLeadingComments(stmt: any, writer: Writer, _ctx: PrintContext, indentLevel: number): boolean; | ||
| /** | ||
| * Check if there's a blank line gap between the last comment and a statement. | ||
| */ | ||
| static emitBlankLineAfterComments(stmt: any, writer: Writer): void; | ||
| /** | ||
| * Check if there's a blank line gap between two statements. | ||
| */ | ||
| static emitBlankLineBetweenStatements(prevStmt: any, currentStmt: any, writer: Writer): void; | ||
| /** | ||
| * Print define (function definition) node | ||
| */ | ||
| static printDefine(node: any, writer: Writer, ctx: PrintContext): void; | ||
| /** | ||
| * Print do block node | ||
| */ | ||
| static printDo(node: any, writer: Writer, ctx: PrintContext): void; | ||
| /** | ||
| * Print for loop node | ||
| */ | ||
| static printForLoop(node: any, writer: Writer, ctx: PrintContext): void; | ||
| /** | ||
| * Print ifBlock node | ||
| */ | ||
| static printIfBlock(node: any, writer: Writer, ctx: PrintContext): void; | ||
| /** | ||
| * Print on block node | ||
| */ | ||
| static printOnBlock(node: any, writer: Writer, ctx: PrintContext): void; | ||
| /** | ||
| * Print prompt block node | ||
| */ | ||
| static printPromptBlock(node: any, writer: Writer, _ctx: PrintContext): void; | ||
| /** | ||
| * Print together block node | ||
| */ | ||
| static printTogether(node: any, writer: Writer, ctx: PrintContext): void; | ||
| } |
| import { CommentWithPosition } from '../../types/Ast.type'; | ||
| export type { CommentWithPosition }; | ||
| import { LineIndex } from './LineIndex'; | ||
| /** | ||
@@ -26,13 +26,5 @@ * Represents a patch operation to apply to source code | ||
| lineIndex: LineIndex; | ||
| originalScript?: string; | ||
| allowExtractOriginalCode?: boolean; | ||
| } | ||
| /** | ||
| * LineIndex interface for fast row/col → offset conversion | ||
| */ | ||
| export interface LineIndex { | ||
| offsetAt(row: number, col: number, exclusive?: boolean): number; | ||
| lineEndOffset(row: number): number; | ||
| hasNewline(row: number): boolean; | ||
| getLine(row: number): string; | ||
| getLines(): string[]; | ||
| lineCount(): number; | ||
| } | ||
| export type { CommentWithPosition, LineIndex }; |
@@ -23,10 +23,2 @@ /** | ||
| /** | ||
| * Increase indentation by one level | ||
| */ | ||
| indentIncrement(): void; | ||
| /** | ||
| * Decrease indentation by one level | ||
| */ | ||
| indentDecrement(): void; | ||
| /** | ||
| * Push text with current indentation | ||
@@ -33,0 +25,0 @@ */ |
| import { Value } from '../utils'; | ||
| export interface ExecutionStepInfo { | ||
| nodeKey: string; | ||
| variables: Record<string, Value>; | ||
| result: Value; | ||
| timestamp: number; | ||
| } | ||
| export interface ExecutionLog { | ||
| message: string; | ||
| nodeKey?: string; | ||
| timestamp: number; | ||
| source?: 'log' | 'say' | string; | ||
| } | ||
| export type LogCallback = (log: ExecutionLog) => void; | ||
| export declare class ExecutionStateTracker { | ||
| private state; | ||
| setState(index: number, state: { | ||
| lastValue: Value; | ||
| beforeValue: Value; | ||
| }): void; | ||
| getState(index: number): { | ||
| lastValue: Value; | ||
| beforeValue: Value; | ||
| } | undefined; | ||
| private steps; | ||
| private logs; | ||
| private nodeStates; | ||
| private indexedStates; | ||
| private onLog; | ||
| setLogCallback(callback: LogCallback | null): void; | ||
| addStep(step: ExecutionStepInfo): void; | ||
| addLog(log: ExecutionLog): void; | ||
| getSteps(): ExecutionStepInfo[]; | ||
| getLogs(): ExecutionLog[]; | ||
| getNodeState(nodeKey: string): ExecutionStepInfo | undefined; | ||
| getState(index: number): any; | ||
| setState(index: number, state: any): void; | ||
| clear(): void; | ||
| } |
@@ -10,2 +10,5 @@ import { Value } from '../utils'; | ||
| private sourceCode; | ||
| private recursionDepth; | ||
| private currentStatement; | ||
| private static readonly MAX_RECURSION_DEPTH; | ||
| /** | ||
@@ -18,5 +21,24 @@ * Debug mode flag - set to true to enable logging | ||
| getCurrentFrame(frameOverride?: Frame): Frame; | ||
| getCurrentStatement(): Statement | null; | ||
| getEnvironment(): Environment; | ||
| getCallStack(): Frame[]; | ||
| /** | ||
| * Compute Levenshtein distance between two strings | ||
| */ | ||
| private levenshteinDistance; | ||
| /** | ||
| * Find similar function names for "did you mean?" suggestions | ||
| */ | ||
| private findSimilarFunctions; | ||
| /** | ||
| * Format "Unknown function" error with suggestions | ||
| */ | ||
| private unknownFunctionError; | ||
| /** | ||
| * Creates a new Executor instance that shares the same environment and call stack, | ||
| * but has its own call stack array to allow parallel execution without stack corruption. | ||
| * The frames themselves (locals Maps) are shared. | ||
| */ | ||
| spawnChild(): Executor; | ||
| /** | ||
| * Execute an event handler with the provided arguments | ||
@@ -37,2 +59,6 @@ * Arguments are available as $1, $2, $3, etc. in the handler body | ||
| /** | ||
| * Get all variables visible in the current frame | ||
| */ | ||
| private getVariableStateInternal; | ||
| /** | ||
| * Reconstructs the original input string from an Arg object. | ||
@@ -166,2 +192,6 @@ * This is useful for commands that need to preserve the original input | ||
| private setVariableAtPath; | ||
| /** | ||
| * Resolve a dynamic key segment to its actual key value | ||
| */ | ||
| private resolveDynamicKey; | ||
| } |
@@ -11,4 +11,7 @@ /** | ||
| export { ExecutionStateTracker } from './ExecutionStateTracker'; | ||
| export type { ExecutionLog, ExecutionStepInfo, LogCallback } from './ExecutionStateTracker'; | ||
| export { ReturnException, BreakException, EndException } from './exceptions'; | ||
| export { RobinPathThread } from './RobinPathThread'; | ||
| export { ASTToCodeConverter } from './code-converter'; | ||
| export { ASTSerializer } from './ASTSerializer'; | ||
| export { ASTToCodeConverter, Printer, LineIndexImpl } from './code-converter'; | ||
| export type { PrintContext, LineIndex } from './code-converter'; |
@@ -60,2 +60,3 @@ /** | ||
| value?: any; | ||
| isContinuation?: boolean; | ||
| } | ||
@@ -62,0 +63,0 @@ /** |
+22
-16
@@ -1,8 +0,16 @@ | ||
| import { Statement, DefineFunction, OnBlock } from '../types/Ast.type'; | ||
| import { Statement, CodePosition, DefineFunction, OnBlock } from '../types/Ast.type'; | ||
| import { Environment } from '../index'; | ||
| export interface ExtractedVariable { | ||
| name: string; | ||
| description?: string; | ||
| initialValue?: any; | ||
| codePos: CodePosition; | ||
| } | ||
| export declare class Parser { | ||
| private tokens; | ||
| private stream; | ||
| private source; | ||
| private extractedFunctions; | ||
| private extractedEventHandlers; | ||
| private extractedVariables; | ||
| private environment; | ||
@@ -32,10 +40,6 @@ private decoratorBuffer; | ||
| /** | ||
| * Parse a statement from a stream (for use in DefineParser) | ||
| * Parse a statement from a stream with hierarchical nodeKey support | ||
| */ | ||
| private parseStatementFromStream; | ||
| /** | ||
| * Parse a comment from a stream (for use in DefineParser) | ||
| */ | ||
| private parseCommentFromStream; | ||
| /** | ||
| * Get extracted function definitions (def/enddef blocks) | ||
@@ -49,19 +53,21 @@ */ | ||
| /** | ||
| * Parse a single statement | ||
| * Get extracted variables (from assignments) | ||
| */ | ||
| private parseStatement; | ||
| getExtractedVariables(): ExtractedVariable[]; | ||
| /** | ||
| * Attach inline comments to a statement if they exist on the same line | ||
| * Track a variable from an assignment statement | ||
| */ | ||
| private attachInlineComments; | ||
| private trackVariable; | ||
| /** | ||
| * Execute parse-time decorators during parsing | ||
| * Parse decorators inject metadata into AST nodes | ||
| * Parse a single statement | ||
| */ | ||
| private executeParseDecorators; | ||
| private parseStatement; | ||
| private parseCommentFromStream; | ||
| private attachInlineComments; | ||
| private countTrailingBlankLines; | ||
| /** | ||
| * Serialize AST to a JSON-serializable format | ||
| * Handles circular references and nested structures properly | ||
| * Recursively assign nodeKeys to body statements | ||
| * This ensures all nested statements have hierarchical nodeKeys for execution tracking | ||
| */ | ||
| private serializeAST; | ||
| private assignBodyNodeKeys; | ||
| } |
@@ -8,2 +8,3 @@ import { Value } from '../utils'; | ||
| private parent; | ||
| private serializer; | ||
| constructor(baseEnvironment: Environment, id: string, parent?: RobinPath); | ||
@@ -40,2 +41,6 @@ /** | ||
| /** | ||
| * Get all variables in this thread as a plain object | ||
| */ | ||
| getVariableState(): Record<string, Value>; | ||
| /** | ||
| * Get the current module name (set by "use" command) | ||
@@ -103,18 +108,2 @@ * Returns null if no module is currently in use | ||
| /** | ||
| * Find the module name for a given function name | ||
| * Returns the module name if found, null otherwise | ||
| */ | ||
| private findModuleName; | ||
| /** | ||
| * Determine the type of a value | ||
| * @param value The value to check | ||
| * @returns The type string: 'string', 'number', 'boolean', 'null', 'object', or 'array' | ||
| */ | ||
| private getValueType; | ||
| private serializeStatement; | ||
| /** | ||
| * Serialize an argument to JSON | ||
| */ | ||
| private serializeArg; | ||
| /** | ||
| * Get all available commands, modules, and functions for this thread | ||
@@ -146,2 +135,4 @@ * Includes thread-local user-defined functions in addition to shared builtins and modules | ||
| description: string; | ||
| author?: string; | ||
| category?: string; | ||
| }>; | ||
@@ -148,0 +139,0 @@ moduleFunctions: Array<{ |
@@ -22,2 +22,5 @@ import { TokenKind, Token } from './Lexer'; | ||
| private consecutiveNextCalls; | ||
| private positionHistory; | ||
| private operationsSinceLastAdvance; | ||
| private lastPositionValue; | ||
| /** | ||
@@ -28,2 +31,7 @@ * Maximum number of consecutive next() calls allowed at the same position before throwing | ||
| /** | ||
| * Maximum number of operations without position advancement before detecting stuck | ||
| * Only counts operations that should advance (next, match, expect, etc.) | ||
| */ | ||
| static readonly MAX_OPERATIONS_WITHOUT_ADVANCE = 100; | ||
| /** | ||
| * Debug mode flag - set to true to enable logging | ||
@@ -48,2 +56,6 @@ * Can be controlled via VITE_DEBUG environment variable or set programmatically | ||
| /** | ||
| * Reset stuck detection counters (useful when manually advancing position) | ||
| */ | ||
| resetStuckDetection(): void; | ||
| /** | ||
| * Set the current position directly | ||
@@ -71,2 +83,8 @@ * @param position - New position | ||
| /** | ||
| * Check if the stream appears to be stuck (no position advancement) | ||
| * @param operation - Name of the operation being performed | ||
| * @throws Error if stuck condition detected | ||
| */ | ||
| private checkStuckCondition; | ||
| /** | ||
| * Check if we're at the end of the token stream | ||
@@ -73,0 +91,0 @@ * @returns True if at EOF or beyond |
+65
-22
| import { extractNamedArgs, Value, AttributePathSegment } from './utils'; | ||
| import { RobinPathThread } from './classes'; | ||
| import { RobinPathThread, ExecutionStateTracker, ExecutionLog } from './classes'; | ||
| import { Statement, Arg, DefineFunction, OnBlock } from './types/Ast.type'; | ||
@@ -9,2 +9,3 @@ /** | ||
| */ | ||
| export declare const ROBINPATH_VERSION = "0.30.0"; | ||
| export interface ModuleAdapter { | ||
@@ -17,4 +18,8 @@ name: string; | ||
| } | ||
| export { Parser, Printer, LineIndexImpl } from './classes'; | ||
| export type { PrintContext, LineIndex } from './classes'; | ||
| export { formatErrorWithContext, createErrorWithContext } from './utils'; | ||
| export type { ExecutionLog, ExecutionStepInfo, LogCallback } from './classes'; | ||
| export type { Value, AttributePathSegment }; | ||
| export type { Statement, Arg, CommandCall, Assignment, ShorthandAssignment, InlineIf, IfBlock, IfTrue, IfFalse, DefineFunction, ScopeBlock, TogetherBlock, ForLoop, ReturnStatement, BreakStatement, OnBlock, CommentStatement, CommentWithPosition, CodePosition, DecoratorCall } from './types/Ast.type'; | ||
| export type { Statement, Arg, CommandCall, Assignment, ShorthandAssignment, InlineIf, IfBlock, IfTrue, IfFalse, DefineFunction, ScopeBlock, TogetherBlock, ForLoop, ReturnStatement, BreakStatement, OnBlock, CommentStatement, ChunkMarkerStatement, CellBlock, PromptBlockStatement, CommentWithPosition, CodePosition, DecoratorCall, } from './types/Ast.type'; | ||
| export type BuiltinCallback = (callbackArgs: Value[]) => Promise<Value> | Value | null; | ||
@@ -37,2 +42,3 @@ export type BuiltinHandler = (args: Value[], callback?: BuiltinCallback | null) => Promise<Value> | Value | null; | ||
| eventHandlers: Map<string, OnBlock[]>; | ||
| stateTracker?: ExecutionStateTracker; | ||
| } | ||
@@ -47,4 +53,4 @@ export interface Frame { | ||
| export { extractNamedArgs }; | ||
| export type DataType = 'string' | 'number' | 'boolean' | 'object' | 'array' | 'null' | 'any'; | ||
| export type FormInputType = 'text' | 'number' | 'textarea' | 'select' | 'checkbox' | 'radio' | 'date' | 'datetime' | 'file' | 'json' | 'code'; | ||
| export type DataType = "string" | "number" | "boolean" | "object" | "array" | "null" | "any"; | ||
| export type FormInputType = "text" | "number" | "textarea" | "select" | "checkbox" | "radio" | "date" | "datetime" | "file" | "json" | "code" | "varname"; | ||
| export interface ParameterMetadata { | ||
@@ -58,2 +64,3 @@ name: string; | ||
| defaultValue?: Value; | ||
| allowedTypes?: string[]; | ||
| children?: ParameterMetadata; | ||
@@ -71,7 +78,12 @@ } | ||
| methods: string[]; | ||
| author?: string; | ||
| category?: string; | ||
| doc_url?: string; | ||
| } | ||
| export declare class RobinPath { | ||
| private static versionLogged; | ||
| private environment; | ||
| private persistentExecutor; | ||
| private lastExecutor; | ||
| private activeExecutor; | ||
| private threads; | ||
@@ -82,2 +94,4 @@ private currentThread; | ||
| private astToCodeConverter; | ||
| private serializer; | ||
| private stateTracker; | ||
| constructor(options?: { | ||
@@ -87,2 +101,19 @@ threadControl?: boolean; | ||
| /** | ||
| * Get execution steps from the last execution | ||
| */ | ||
| getExecutionSteps(): import('./classes').ExecutionStepInfo[]; | ||
| /** | ||
| * Get execution logs from the last execution | ||
| */ | ||
| getExecutionLogs(): ExecutionLog[]; | ||
| /** | ||
| * Set a callback for real-time log notifications | ||
| * The callback is called immediately when a log is added during execution | ||
| */ | ||
| setLogCallback(callback: ((log: ExecutionLog) => void) | null): void; | ||
| /** | ||
| * Clear execution state | ||
| */ | ||
| clearExecutionState(): void; | ||
| /** | ||
| * Native modules registry | ||
@@ -265,2 +296,4 @@ * Add new modules here to auto-load them | ||
| description: string; | ||
| author?: string; | ||
| category?: string; | ||
| }>; | ||
@@ -285,3 +318,3 @@ moduleFunctions: Array<{ | ||
| needsMore: boolean; | ||
| waitingFor?: 'endif' | 'enddef' | 'endfor' | 'enddo' | 'endon' | 'subexpr' | 'paren' | 'object' | 'array'; | ||
| waitingFor?: "endif" | "enddef" | "endfor" | "enddo" | "endon" | "subexpr" | "paren" | "object" | "array"; | ||
| }>; | ||
@@ -303,21 +336,24 @@ /** | ||
| /** | ||
| * Find the module name for a given function name | ||
| * Returns the module name if found, null otherwise | ||
| * @param functionName The function name to look up | ||
| * @param currentModuleContext Optional module context from "use" command (for getAST) | ||
| */ | ||
| private findModuleName; | ||
| /** | ||
| * Serialize a statement to JSON without execution state | ||
| * Serialize a statement to JSON | ||
| * @param stmt The statement to serialize | ||
| * @param currentModuleContext Optional module context from "use" command (for getAST) | ||
| * @param currentModuleContext Optional module context | ||
| * @param lastValue Optional execution state | ||
| * @param nodeKey Optional node key | ||
| */ | ||
| private serializeStatement; | ||
| /** | ||
| * Determine the type of a value | ||
| * @param value The value to check | ||
| * @returns The type string: 'string', 'number', 'boolean', 'null', 'object', or 'array' | ||
| * Get the complete structure of the script in a tree format | ||
| * Includes main body, functions, event handlers, and variables | ||
| */ | ||
| private getValueType; | ||
| getScriptStructure(script: string): Promise<any>; | ||
| /** | ||
| * Get extracted variables from the script (parsed, not executed) | ||
| * Returns variable names with optional description and initial value | ||
| */ | ||
| getExtractedVariables(script: string): Promise<Array<{ | ||
| name: string; | ||
| description?: string; | ||
| initialValue?: any; | ||
| }>>; | ||
| /** | ||
| * Update source code based on AST changes | ||
@@ -330,7 +366,10 @@ * Uses precise character-level positions (codePos.startRow/startCol/endRow/endCol) to update code | ||
| */ | ||
| updateCodeFromAST(originalScript: string, ast: any[]): string; | ||
| updateCodeFromAST(originalScript: string, ast: any[]): Promise<string>; | ||
| /** | ||
| * Serialize an argument to JSON | ||
| * Reconstruct code from an AST node | ||
| * @param node The AST node (serialized) | ||
| * @param indentLevel Indentation level for nested code | ||
| * @returns Reconstructed code string, or null if cannot be reconstructed | ||
| */ | ||
| private serializeArg; | ||
| reconstructCodeFromASTNode(node: any, indentLevel?: number): string | null; | ||
| /** | ||
@@ -442,2 +481,6 @@ * Execute a RobinPath script | ||
| /** | ||
| * Get all variables as a plain object | ||
| */ | ||
| getVariableState(): Record<string, Value>; | ||
| /** | ||
| * Get the next statement index that would execute after a given statement. | ||
@@ -452,5 +495,5 @@ * This method analyzes the AST structure to determine execution flow. | ||
| getNextStatementIndex(statements: Statement[], currentIndex: number, context?: { | ||
| ifBlockBranch?: 'then' | 'elseif' | 'else' | null; | ||
| ifBlockBranch?: "then" | "elseif" | "else" | null; | ||
| forLoopIteration?: number; | ||
| }): number; | ||
| } |
@@ -25,6 +25,14 @@ import { TokenStream } from '../classes/TokenStream'; | ||
| /** | ||
| * Parse a simple fallback value (string, number, boolean, null) | ||
| */ | ||
| private static parseFallbackValue; | ||
| /** | ||
| * Parse the value part of an assignment | ||
| * Returns the assignment data and the end token | ||
| */ | ||
| /** | ||
| * Check if there's a binary operator ahead that would indicate we need parseExpression | ||
| */ | ||
| private static isBinaryOperatorAhead; | ||
| private static parseAssignmentValue; | ||
| } |
@@ -50,10 +50,8 @@ import { TokenStream } from '../classes/TokenStream'; | ||
| * Parse "into $var" syntax | ||
| * Handles "into" on the same line or next line (for multiline calls) | ||
| */ | ||
| private static parseInto; | ||
| /** | ||
| * Parse callback block (with only - do blocks are standalone statements, not callbacks) | ||
| * Only accepts callbacks on the same line as the command (does not skip newlines) | ||
| * Parse callback block (with only) | ||
| */ | ||
| private static parseCallback; | ||
| } |
| import { TokenStream } from '../classes/TokenStream'; | ||
| import { DefineFunction, Statement, DecoratorCall } from '../types/Ast.type'; | ||
| import { Statement, DefineFunction, DecoratorCall } from '../types/Ast.type'; | ||
| import { Environment } from '../index'; | ||
@@ -16,3 +16,4 @@ export declare class DefineParser { | ||
| */ | ||
| static parse(stream: TokenStream, parseStatement: (stream: TokenStream) => Statement | null, parseComment: (stream: TokenStream) => Statement | null, decorators?: DecoratorCall[], environment?: Environment | null): Promise<DefineFunction>; | ||
| static parse(stream: TokenStream, parseStatement: (stream: TokenStream) => Statement | null, _parseComment: (stream: TokenStream) => Statement | null, // eslint-disable-line @typescript-eslint/no-unused-vars | ||
| decorators?: DecoratorCall[], environment?: Environment | null): Promise<DefineFunction>; | ||
| } |
| import { TokenStream } from '../classes/TokenStream'; | ||
| import { OnBlock, Statement, DecoratorCall } from '../types/Ast.type'; | ||
| import { Statement, OnBlock, DecoratorCall } from '../types/Ast.type'; | ||
| import { Environment } from '../index'; | ||
@@ -4,0 +4,0 @@ export declare class EventParser { |
@@ -23,3 +23,3 @@ import { TokenStream } from '../classes/TokenStream'; | ||
| */ | ||
| static parse(stream: TokenStream, parseStatement: (stream: TokenStream) => Statement | null, parseComment: (stream: TokenStream) => Statement | null, decorators?: DecoratorCall[]): ScopeBlock; | ||
| static parse(stream: TokenStream, parseStatement: (stream: TokenStream) => Statement | null, _parseComment: (stream: TokenStream) => Statement | null, decorators?: DecoratorCall[]): ScopeBlock; | ||
| } |
@@ -17,6 +17,6 @@ import { TokenStream } from '../classes/TokenStream'; | ||
| * Parse a subexpression from TokenStream | ||
| * Expects stream to be positioned at the '$' token | ||
| * Expects stream to be positioned at the '$(' token | ||
| * Syntax: $( ... ) | ||
| * | ||
| * @param stream - TokenStream positioned at the '$' token | ||
| * @param stream - TokenStream positioned at the '$(' token | ||
| * @param context - Context with helper methods | ||
@@ -29,3 +29,2 @@ * @returns Parsed SubexpressionExpression | ||
| * Subexpressions must start with SUBEXPRESSION_OPEN ($() | ||
| * Regular parentheses ( ) are handled by other parsers | ||
| * | ||
@@ -32,0 +31,0 @@ * @param stream - TokenStream to check |
+112
-2
@@ -24,4 +24,24 @@ import { Value, AttributePathSegment } from '../utils/types'; | ||
| type: 'comment'; | ||
| nodeKey?: string; | ||
| comments: CommentWithPosition[]; | ||
| lineNumber: number; | ||
| /** | ||
| * Number of blank lines after this statement (for preserving formatting). | ||
| * | ||
| * **Semantics:** | ||
| * - `undefined` or `0`: No trailing blank lines (statement immediately followed by next) | ||
| * - `1`: One blank line after statement (two consecutive newlines: `\n\n`) | ||
| * - `2`: Two blank lines after statement (three consecutive newlines: `\n\n\n`) | ||
| * - ... and so on | ||
| * | ||
| * **For the LAST statement in a file:** | ||
| * - `undefined` or `0`: File does NOT end with a newline | ||
| * - `1`: File ends with exactly one newline (no blank line at EOF) | ||
| * - `2`: File ends with one blank line (two newlines at EOF) | ||
| * - ... and so on | ||
| * | ||
| * **Note:** The statement's own ending newline is NOT counted in trailingBlankLines. | ||
| * Each statement implicitly ends with `\n`. This field only tracks EXTRA blank lines. | ||
| */ | ||
| trailingBlankLines?: number; | ||
| } | ||
@@ -177,5 +197,7 @@ /** | ||
| type: 'command'; | ||
| nodeKey?: string; | ||
| name: string; | ||
| args: Arg[]; | ||
| syntaxType?: 'space' | 'parentheses' | 'named-parentheses' | 'multiline-parentheses'; | ||
| isTaggedTemplate?: boolean; | ||
| decorators?: DecoratorCall[]; | ||
@@ -188,2 +210,3 @@ into?: { | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
@@ -196,2 +219,3 @@ } | ||
| type: 'assignment'; | ||
| nodeKey?: string; | ||
| targetName: string; | ||
@@ -203,4 +227,12 @@ targetPath?: AttributePathSegment[]; | ||
| isLastValue?: boolean; | ||
| isSet?: boolean; | ||
| isVar?: boolean; | ||
| isConst?: boolean; | ||
| hasAs?: boolean; | ||
| isImplicit?: boolean; | ||
| fallbackValue?: Value; | ||
| fallbackValueType?: 'string' | 'number' | 'boolean' | 'null'; | ||
| comments?: CommentWithPosition[]; | ||
| decorators?: DecoratorCall[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
@@ -213,4 +245,6 @@ } | ||
| type: 'shorthand'; | ||
| nodeKey?: string; | ||
| targetName: string; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
@@ -223,2 +257,3 @@ } | ||
| type: 'inlineIf'; | ||
| nodeKey?: string; | ||
| condition: Expression; | ||
@@ -228,2 +263,3 @@ command: Statement; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
@@ -236,11 +272,17 @@ } | ||
| type: 'ifBlock'; | ||
| nodeKey?: string; | ||
| condition: Expression; | ||
| thenBranch: Statement[]; | ||
| elseBranch?: Statement[]; | ||
| elseHasThen?: boolean; | ||
| elseKeywordPos?: CodePosition; | ||
| elseifBranches?: Array<{ | ||
| condition: Expression; | ||
| body: Statement[]; | ||
| hasThen?: boolean; | ||
| keywordPos?: CodePosition; | ||
| }>; | ||
| decorators?: DecoratorCall[]; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
@@ -253,4 +295,6 @@ } | ||
| type: 'ifTrue'; | ||
| nodeKey?: string; | ||
| command: Statement; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
@@ -263,4 +307,6 @@ } | ||
| type: 'ifFalse'; | ||
| nodeKey?: string; | ||
| command: Statement; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
@@ -273,2 +319,3 @@ } | ||
| type: 'define'; | ||
| nodeKey?: string; | ||
| name: string; | ||
@@ -279,2 +326,3 @@ paramNames: string[]; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
@@ -287,2 +335,3 @@ } | ||
| type: 'do'; | ||
| nodeKey?: string; | ||
| paramNames?: string[]; | ||
@@ -296,2 +345,3 @@ body: Statement[]; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
@@ -304,5 +354,7 @@ } | ||
| type: 'together'; | ||
| nodeKey?: string; | ||
| blocks: ScopeBlock[]; | ||
| decorators?: DecoratorCall[]; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
@@ -315,7 +367,13 @@ } | ||
| type: 'forLoop'; | ||
| nodeKey?: string; | ||
| varName: string; | ||
| iterable: Expression; | ||
| iterable?: Expression; | ||
| from?: Expression; | ||
| to?: Expression; | ||
| step?: Expression; | ||
| keyVarName?: string; | ||
| body: Statement[]; | ||
| decorators?: DecoratorCall[]; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
@@ -328,4 +386,6 @@ } | ||
| type: 'return'; | ||
| nodeKey?: string; | ||
| value?: Arg; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
@@ -338,3 +398,5 @@ } | ||
| type: 'break'; | ||
| nodeKey?: string; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
@@ -347,3 +409,5 @@ } | ||
| type: 'continue'; | ||
| nodeKey?: string; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
@@ -356,2 +420,3 @@ } | ||
| type: 'onBlock'; | ||
| nodeKey?: string; | ||
| eventName: string; | ||
@@ -361,7 +426,52 @@ body: Statement[]; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| codePos: CodePosition; | ||
| } | ||
| /** | ||
| * Represents a cell block (---cell <cellType> <meta...>--- ... ---end---) | ||
| */ | ||
| export interface CellBlock { | ||
| type: 'cell'; | ||
| nodeKey?: string; | ||
| cellType: string; | ||
| meta: Record<string, string>; | ||
| rawBody: string; | ||
| body?: Statement[]; | ||
| headerPos: CodePosition; | ||
| bodyPos: CodePosition; | ||
| codePos: CodePosition; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| } | ||
| /** | ||
| * Represents a prompt block statement (--- ... ---) | ||
| */ | ||
| export interface PromptBlockStatement { | ||
| type: 'prompt_block'; | ||
| nodeKey?: string; | ||
| rawText: string; | ||
| fence: '---'; | ||
| codePos: CodePosition; | ||
| openPos: CodePosition; | ||
| bodyPos: CodePosition; | ||
| closePos: CodePosition; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| } | ||
| /** | ||
| * Represents a chunk marker statement (--- chunk:<id> ---) | ||
| */ | ||
| export interface ChunkMarkerStatement { | ||
| type: 'chunk_marker'; | ||
| nodeKey?: string; | ||
| id: string; | ||
| meta?: Record<string, string>; | ||
| codePos: CodePosition; | ||
| raw?: string; | ||
| comments?: CommentWithPosition[]; | ||
| trailingBlankLines?: number; | ||
| } | ||
| /** | ||
| * Union type representing all possible statement types in the AST | ||
| */ | ||
| export type Statement = CommandCall | Assignment | ShorthandAssignment | InlineIf | IfBlock | IfTrue | IfFalse | DefineFunction | ScopeBlock | TogetherBlock | ForLoop | ReturnStatement | BreakStatement | ContinueStatement | OnBlock | CommentStatement; | ||
| export type Statement = CommandCall | Assignment | ShorthandAssignment | InlineIf | IfBlock | IfTrue | IfFalse | DefineFunction | ScopeBlock | TogetherBlock | ForLoop | ReturnStatement | BreakStatement | ContinueStatement | OnBlock | CommentStatement | ChunkMarkerStatement | CellBlock | PromptBlockStatement; |
@@ -32,4 +32,11 @@ import { AttributePathSegment } from './types'; | ||
| }; | ||
| /** | ||
| * Parse a dynamic key from inside brackets: [$varName] or [$varName.property] | ||
| * @param str The full string being parsed | ||
| * @param pos Position right after the '$' character | ||
| * @returns The parsed segment and the position after the closing ']' | ||
| */ | ||
| private static parseDynamicKey; | ||
| static isLastValue(token: string): boolean; | ||
| static isPositionalParam(token: string): boolean; | ||
| } |
@@ -11,2 +11,6 @@ /** | ||
| index: number; | ||
| } | { | ||
| type: 'dynamicKey'; | ||
| variable: string; | ||
| varPath?: AttributePathSegment[]; | ||
| }; |
@@ -15,1 +15,12 @@ import { Value } from './types'; | ||
| export declare function isTruthy(val: Value): boolean; | ||
| /** | ||
| * Get the type of a value | ||
| */ | ||
| export declare function getValueType(value: Value): 'string' | 'number' | 'boolean' | 'null' | 'object' | 'array'; | ||
| /** | ||
| * Attempt to convert a value to a different type | ||
| * @param value The value to convert | ||
| * @param targetType The target type to convert to | ||
| * @returns The converted value, or null if conversion fails | ||
| */ | ||
| export declare function convertValueType(value: Value, targetType: 'string' | 'number' | 'boolean' | 'null' | 'object' | 'array'): Value | null; |
+7
-1
| { | ||
| "name": "@wiredwp/robinpath", | ||
| "description": "RobinPath - A lightweight, fast, and easy-to-use scripting language for automation and data processing.", | ||
| "version": "0.30.0", | ||
| "version": "0.30.1", | ||
| "author": "Ryan Lee <ryan@wiredwp.com>", | ||
@@ -24,3 +24,7 @@ "type": "module", | ||
| "test": "npm run build && node test/run.js", | ||
| "test:coverage": "npm run build && c8 node test/run.js", | ||
| "test:coverage:report": "c8 report --reporter=html --reporter=text", | ||
| "test:watch": "nodemon --watch src --watch test --ext ts,js,robin --exec 'npm run test'", | ||
| "test-perform": "npm run build && node test/run-performance.js", | ||
| "test-code": "npm run build && node test/test-code.js", | ||
| "cli": "npm run build && node bin/robinpath.js" | ||
@@ -38,2 +42,4 @@ }, | ||
| "devDependencies": { | ||
| "c8": "^10.1.3", | ||
| "nodemon": "^3.1.9", | ||
| "typescript": "~5.9.3", | ||
@@ -40,0 +46,0 @@ "vite": "^7.2.4", |
+16
-7
@@ -655,13 +655,22 @@ # RobinPath | ||
| ```robinpath | ||
| for $i in range 1 5 | ||
| # Iterate over a range | ||
| for $i from 1 to 5 | ||
| log "Iteration:" $i | ||
| endfor | ||
| ``` | ||
| **For loop with array:** | ||
| ```robinpath | ||
| $numbers = range 10 12 | ||
| for $num in $numbers | ||
| log "Number:" $num | ||
| # Iterate with custom step and key (index) | ||
| for $a from 0 to 10 step 2 key $index | ||
| log "value: " + $a + ", index: " + $index | ||
| endfor | ||
| # Range parameters can be in any order | ||
| for $x by 5 to 100 from 0 | ||
| log $x | ||
| endfor | ||
| # Iterate over an array | ||
| $numbers = [10, 11, 12] | ||
| for $num in $numbers key $i | ||
| log "Number " + $i + ": " + $num | ||
| endfor | ||
| ``` | ||
@@ -668,0 +677,0 @@ |
| /** | ||
| * ASTToCodeConverter - Converts AST nodes back to source code | ||
| * | ||
| * This class handles the conversion of AST (Abstract Syntax Tree) nodes | ||
| * back into RobinPath source code strings. It provides methods for: | ||
| * - Updating source code based on AST changes | ||
| * - Reconstructing code from individual AST nodes | ||
| * - Handling comments, indentation, and code positioning | ||
| */ | ||
| export declare class ASTToCodeConverter { | ||
| /** | ||
| * Update source code based on AST changes | ||
| * Uses precise character-level positions (codePos.startRow/startCol/endRow/endCol) to update code | ||
| * Nested nodes are reconstructed as part of their parent's code | ||
| * @param originalScript The original source code | ||
| * @param ast The modified AST array (top-level nodes only) | ||
| * @returns Updated source code | ||
| */ | ||
| updateCodeFromAST(originalScript: string, ast: any[]): string; | ||
| /** | ||
| * Reconstruct code string from an AST node | ||
| * @param node The AST node (serialized) | ||
| * @param indentLevel Indentation level for nested code | ||
| * @returns Reconstructed code string, or null if cannot be reconstructed | ||
| */ | ||
| private reconstructCodeFromASTNode; | ||
| /** | ||
| * Reconstruct code string from an Arg object | ||
| */ | ||
| private reconstructArgCode; | ||
| /** | ||
| * Reconstruct comment code from a CommentWithPosition object | ||
| */ | ||
| private reconstructCommentCode; | ||
| /** | ||
| * Convert row/column position to character offset in script | ||
| * @param script The script string | ||
| * @param row Zero-based row number | ||
| * @param col Zero-based column number | ||
| * @param exclusive If true, return offset one past the column (for end positions) | ||
| * @returns Character offset in the script string | ||
| */ | ||
| private rowColToCharOffset; | ||
| /** | ||
| * Get the type of a value | ||
| */ | ||
| private getValueType; | ||
| /** | ||
| * Attempt to convert a value to a different type | ||
| * @param value The value to convert | ||
| * @param targetType The target type to convert to | ||
| * @returns The converted value, or null if conversion fails | ||
| */ | ||
| private convertValueType; | ||
| } |
| import { Statement } from '../../types/Ast.type'; | ||
| import { CommentLayout as CommentLayoutType, LineIndex } from './types'; | ||
| export declare class CommentLayoutNormalizer { | ||
| /** | ||
| * Normalize comment layout for a statement | ||
| */ | ||
| static normalize(node: Statement, lineIndex: LineIndex): CommentLayoutType; | ||
| } |
| import { Patch } from './types'; | ||
| export declare class PatchApplier { | ||
| /** | ||
| * Apply patches to source code | ||
| * Patches are sorted descending by startOffset and applied from end to start | ||
| * to prevent character position shifts from affecting subsequent replacements | ||
| */ | ||
| static apply(originalScript: string, patches: Patch[]): string; | ||
| /** | ||
| * Validate that patches don't overlap | ||
| * @internal This method is kept for potential future use or manual invocation | ||
| */ | ||
| static validatePatches(patches: Patch[]): void; | ||
| } |
| import { Statement } from '../../types/Ast.type'; | ||
| import { Patch } from './types'; | ||
| export declare class PatchPlanner { | ||
| private lineIndex; | ||
| private patches; | ||
| constructor(originalScript: string); | ||
| /** | ||
| * Plan patches for all nodes in the AST | ||
| */ | ||
| planPatches(ast: Statement[]): Patch[]; | ||
| /** | ||
| * Plan a patch for a single node | ||
| */ | ||
| private planPatchForNode; | ||
| /** | ||
| * Plan patch for leading comments (non-overlapping case) | ||
| */ | ||
| private planPatchForLeadingComments; | ||
| /** | ||
| * Generate replacement without leading comments (for non-overlapping case) | ||
| */ | ||
| private generateReplacementWithoutLeadingComments; | ||
| /** | ||
| * Plan patch for a standalone comment node | ||
| */ | ||
| private planPatchForCommentNode; | ||
| /** | ||
| * Find the stop row for comment blank line inclusion | ||
| */ | ||
| private findStopRowForComment; | ||
| /** | ||
| * Plan patch to remove existing comments | ||
| */ | ||
| private planPatchToRemoveComments; | ||
| /** | ||
| * Compute the range for a statement region | ||
| */ | ||
| private computeStatementRange; | ||
| /** | ||
| * Generate replacement text for a node | ||
| */ | ||
| private generateReplacement; | ||
| } |
| import { PrintContext } from '../types'; | ||
| export declare function printArg(arg: any, _ctx: PrintContext): string | null; | ||
| /** | ||
| * Print a variable reference | ||
| */ | ||
| export declare function printVarRef(name: string, path?: any[]): string; | ||
| /** | ||
| * Print an into target | ||
| */ | ||
| export declare function printIntoTarget(targetName: string, targetPath?: any[]): string; |
| import { PrintContext } from '../types'; | ||
| import { Writer } from '../Writer'; | ||
| export declare function printAssignment(node: any, writer: Writer, ctx: PrintContext): void; |
| import { PrintContext } from '../types'; | ||
| import { Writer } from '../Writer'; | ||
| export declare function printCommand(node: any, writer: Writer, ctx: PrintContext): void; |
| import { PrintContext } from '../types'; | ||
| import { Writer } from '../Writer'; | ||
| export declare function printComment(node: any, writer: Writer, _ctx: PrintContext): void; |
| import { PrintContext } from '../types'; | ||
| import { Writer } from '../Writer'; | ||
| export declare function printDefine(node: any, writer: Writer, ctx: PrintContext): void; |
| import { PrintContext } from '../types'; | ||
| import { Writer } from '../Writer'; | ||
| export declare function printDo(node: any, writer: Writer, ctx: PrintContext): void; |
| import { PrintContext } from '../types'; | ||
| import { Writer } from '../Writer'; | ||
| export declare function printForLoop(node: any, writer: Writer, ctx: PrintContext): void; |
| import { PrintContext } from '../types'; | ||
| import { Writer } from '../Writer'; | ||
| export declare function printIfBlock(node: any, writer: Writer, ctx: PrintContext): void; |
Sorry, the diff of this file is too big to display
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
597048
16.65%17251
15.09%857
1.06%5
66.67%65
-7.14%2
100%