meld
Version:
Meld: A template language for LLM prompts
1,493 lines (1,464 loc) • 80.1 kB
text/typescript
import { MeldNode, DirectiveNode } from 'meld-spec';
import * as fsExtra from 'fs-extra';
import { Stats } from 'fs-extra';
import { Stats as Stats$1 } from 'fs';
import * as path from 'path';
/**
* @package
* Core event system for state tracking.
*
* @remarks
* Provides event emission and handling for state operations.
*/
/**
* Core state event types as defined in the instrumentation plan
*/
type StateEventType = 'create' | 'clone' | 'transform' | 'merge' | 'error';
/**
* Base state event interface
*/
interface StateEvent {
type: StateEventType;
stateId: string;
source: string;
timestamp: number;
location?: {
file?: string;
line?: number;
column?: number;
};
}
/**
* Event handler function type
*/
type StateEventHandler = (event: StateEvent) => void | Promise<void>;
/**
* Event filter predicate
*/
type StateEventFilter = (event: StateEvent) => boolean;
/**
* Handler registration options
*/
interface StateEventHandlerOptions {
filter?: StateEventFilter;
}
/**
* Core state event service interface
*/
interface IStateEventService {
/**
* Register an event handler with optional filtering
*/
on(type: StateEventType, handler: StateEventHandler, options?: StateEventHandlerOptions): void;
/**
* Remove an event handler
*/
off(type: StateEventType, handler: StateEventHandler): void;
/**
* Emit a state event
*/
emit(event: StateEvent): Promise<void>;
/**
* Get all registered handlers for an event type
*/
getHandlers(type: StateEventType): Array<{
handler: StateEventHandler;
options?: StateEventHandlerOptions;
}>;
}
/**
* @package
* Interface for state tracking service.
*/
interface IStateTrackingService {
/**
* Register a state with the tracking service.
* @param metadata - The state metadata to register
*/
registerState(metadata: Partial<StateMetadata>): void;
/**
* Add a relationship between two states.
* @param sourceId - The source state ID
* @param targetId - The target state ID
* @param type - The type of relationship
*/
addRelationship(sourceId: string, targetId: string, type: 'parent-child' | 'merge-source' | 'merge-target'): void;
/**
* Get the complete lineage of a state from root to the given state.
* @param stateId - The ID of the state to get lineage for
* @param visited - Set of visited states to prevent cycles
* @returns Array of state IDs representing the lineage from root to target state
*/
getStateLineage(stateId: string, visited?: Set<string>): string[];
/**
* Get all descendants of a state.
* @param stateId - The ID of the state to get descendants for
* @param visited - Set of visited states to prevent cycles
* @returns Array of state IDs representing all descendants
*/
getStateDescendants(stateId: string, visited?: Set<string>): string[];
/**
* Get all registered states.
* @returns Array of state metadata for all registered states
*/
getAllStates(): StateMetadata[];
/**
* Get metadata for a specific state.
* @param stateId - The ID of the state to get metadata for
* @returns The state metadata or undefined if not found
*/
getStateMetadata(stateId: string): StateMetadata | undefined;
/**
* Track a context boundary between two states.
* @param sourceStateId - The source state ID
* @param targetStateId - The target state ID
* @param boundaryType - The type of boundary
* @param filePath - Optional file path associated with the boundary
*/
trackContextBoundary(sourceStateId: string, targetStateId: string, boundaryType: 'import' | 'embed', filePath?: string): void;
/**
* Track a variable crossing between two states.
* @param sourceStateId - The source state ID
* @param targetStateId - The target state ID
* @param variableName - The name of the variable
* @param variableType - The type of variable
* @param alias - Optional alias for the variable in the target state
*/
trackVariableCrossing(sourceStateId: string, targetStateId: string, variableName: string, variableType: 'text' | 'data' | 'path' | 'command', alias?: string): void;
/**
* Get all context boundaries.
* @returns Array of context boundaries
*/
getContextBoundaries(): ContextBoundary[];
/**
* Get variable crossings for a state.
* @param stateId - The ID of the state to get variable crossings for
* @returns Array of variable crossings
*/
getVariableCrossings(stateId: string): VariableCrossing[];
/**
* Get the context hierarchy for a state.
* @param rootStateId - The ID of the root state
* @returns Context hierarchy information
*/
getContextHierarchy(rootStateId: string): ContextHierarchyInfo;
}
/**
* Metadata for a state instance.
*/
interface StateMetadata {
id: string;
parentId?: string;
source: 'new' | 'clone' | 'child' | 'merge' | 'implicit';
filePath?: string;
transformationEnabled: boolean;
createdAt: number;
lastModified?: number;
childStates?: string[];
}
/**
* Represents a relationship between states.
*/
interface StateRelationship {
sourceId?: string;
targetId: string;
type: 'parent-child' | 'merge-source' | 'merge-target';
}
/**
* Represents a context boundary between states.
*/
interface ContextBoundary {
sourceStateId: string;
targetStateId: string;
boundaryType: 'import' | 'embed';
timestamp: number;
filePath?: string;
}
/**
* Represents a variable crossing between states.
*/
interface VariableCrossing {
sourceStateId: string;
targetStateId: string;
variableName: string;
variableType: 'text' | 'data' | 'path' | 'command';
timestamp: number;
alias?: string;
}
/**
* Information about the context hierarchy.
*/
interface ContextHierarchyInfo {
states: StateMetadata[];
boundaries: ContextBoundary[];
variableCrossings: VariableCrossing[];
}
/**
* Options for selective transformation
*/
interface TransformationOptions {
variables?: boolean;
directives?: boolean;
commands?: boolean;
imports?: boolean;
}
interface IStateService {
setEventService(eventService: IStateEventService): void;
setTrackingService(trackingService: IStateTrackingService): void;
getStateId(): string | undefined;
getTextVar(name: string): string | undefined;
setTextVar(name: string, value: string): void;
getAllTextVars(): Map<string, string>;
getLocalTextVars(): Map<string, string>;
getDataVar(name: string): unknown;
setDataVar(name: string, value: unknown): void;
getAllDataVars(): Map<string, unknown>;
getLocalDataVars(): Map<string, unknown>;
getPathVar(name: string): string | undefined;
setPathVar(name: string, value: string): void;
getAllPathVars(): Map<string, string>;
getCommand(name: string): {
command: string;
options?: Record<string, unknown>;
} | undefined;
setCommand(name: string, command: string | {
command: string;
options?: Record<string, unknown>;
}): void;
getAllCommands(): Map<string, {
command: string;
options?: Record<string, unknown>;
}>;
getNodes(): MeldNode[];
addNode(node: MeldNode): void;
appendContent(content: string): void;
getTransformedNodes(): MeldNode[];
setTransformedNodes(nodes: MeldNode[]): void;
transformNode(original: MeldNode, transformed: MeldNode): void;
isTransformationEnabled(): boolean;
enableTransformation(options?: TransformationOptions | boolean): void;
shouldTransform(type: keyof TransformationOptions): boolean;
getTransformationOptions(): TransformationOptions;
getCommandOutput(command: string): string | undefined;
hasTransformationSupport(): boolean;
addImport(path: string): void;
removeImport(path: string): void;
hasImport(path: string): boolean;
getImports(): Set<string>;
getCurrentFilePath(): string | null;
setCurrentFilePath(path: string): void;
hasLocalChanges(): boolean;
getLocalChanges(): string[];
setImmutable(): void;
readonly isImmutable: boolean;
createChildState(): IStateService;
mergeChildState(childState: IStateService): void;
clone(): IStateService;
}
interface IValidationService {
/**
* Validate a directive node against its schema and constraints
* @throws {MeldDirectiveError} If validation fails
*/
validate(node: DirectiveNode): Promise<void>;
/**
* Register a validator function for a specific directive kind
*/
registerValidator(kind: string, validator: (node: DirectiveNode) => Promise<void>): void;
/**
* Remove a validator for a specific directive kind
*/
removeValidator(kind: string): void;
/**
* Check if a validator exists for a specific directive kind
*/
hasValidator(kind: string): boolean;
/**
* Get all registered directive kinds that can be validated
*/
getRegisteredDirectiveKinds(): string[];
}
interface IFileSystem {
readFile(path: string): Promise<string>;
writeFile(path: string, content: string): Promise<void>;
exists(path: string): Promise<boolean>;
stat(path: string): Promise<Stats>;
readDir(path: string): Promise<string[]>;
mkdir(path: string): Promise<void>;
isDirectory(path: string): Promise<boolean>;
isFile(path: string): Promise<boolean>;
watch(path: string, options?: {
recursive?: boolean;
}): AsyncIterableIterator<{
filename: string;
eventType: string;
}>;
executeCommand(command: string, options?: {
cwd?: string;
}): Promise<{
stdout: string;
stderr: string;
}>;
isTestEnvironment?: boolean;
}
interface IFileSystemService {
readFile(filePath: string): Promise<string>;
writeFile(filePath: string, content: string): Promise<void>;
exists(filePath: string): Promise<boolean>;
stat(filePath: string): Promise<Stats>;
isFile(filePath: string): Promise<boolean>;
readDir(dirPath: string): Promise<string[]>;
ensureDir(dirPath: string): Promise<void>;
isDirectory(filePath: string): Promise<boolean>;
watch(path: string, options?: {
recursive?: boolean;
}): AsyncIterableIterator<{
filename: string;
eventType: string;
}>;
getCwd(): string;
dirname(filePath: string): string;
executeCommand(command: string, options?: {
cwd?: string;
}): Promise<{
stdout: string;
stderr: string;
}>;
setFileSystem(fileSystem: IFileSystem): void;
getFileSystem(): IFileSystem;
}
/**
* Adapter to use Node's fs-extra as our IFileSystem implementation
*/
declare class NodeFileSystem implements IFileSystem {
isTestEnvironment: boolean;
readFile(path: string): Promise<string>;
writeFile(path: string, content: string): Promise<void>;
exists(path: string): Promise<boolean>;
stat(path: string): Promise<Stats$1>;
readDir(path: string): Promise<string[]>;
mkdir(path: string): Promise<void>;
isDirectory(path: string): Promise<boolean>;
isFile(path: string): Promise<boolean>;
watch(path: string, options?: {
recursive?: boolean;
}): AsyncIterableIterator<{
filename: string;
eventType: string;
}>;
executeCommand(command: string, options?: {
cwd?: string;
}): Promise<{
stdout: string;
stderr: string;
}>;
}
type OutputFormat = 'markdown' | 'xml';
interface OutputOptions {
/**
* Whether to include state variables in the output
* @default false
*/
includeState?: boolean;
/**
* Whether to preserve original formatting (whitespace, newlines)
* @default true
*/
preserveFormatting?: boolean;
/**
* Custom format-specific options
*/
formatOptions?: Record<string, unknown>;
}
interface IOutputService {
/**
* Check if this service can access transformed nodes
* @returns true if transformed nodes can be accessed
*/
canAccessTransformedNodes(): boolean;
/**
* Convert Meld nodes and state to the specified output format.
* If state.isTransformationEnabled() is true and state.getTransformedNodes() is available,
* the transformed nodes will be used instead of the input nodes.
*
* In non-transformation mode:
* - Definition directives (@text, @data, @path, @import, @define) are omitted
* - Execution directives (@run, @embed) show placeholders
*
* In transformation mode:
* - All directives are replaced with their transformed results
* - Plain text and code fences are preserved as-is
*
* @throws {MeldOutputError} If conversion fails
*/
convert(nodes: MeldNode[], state: IStateService, format: OutputFormat, options?: OutputOptions): Promise<string>;
/**
* Register a custom format converter
*/
registerFormat(format: string, converter: (nodes: MeldNode[], state: IStateService, options?: OutputOptions) => Promise<string>): void;
/**
* Check if a format is supported
*/
supportsFormat(format: string): boolean;
/**
* Get a list of all supported formats
*/
getSupportedFormats(): string[];
}
interface IParserService {
/**
* Parse Meld content into an AST using meld-ast.
* @param content The Meld content to parse
* @returns A promise that resolves to an array of MeldNodes representing the AST
* @throws {MeldParseError} If the content cannot be parsed
*/
parse(content: string): Promise<MeldNode[]>;
/**
* Parse Meld content and provide location information for each node.
* This is useful for error reporting and source mapping.
* @param content The Meld content to parse
* @param filePath Optional file path for better error messages
* @returns A promise that resolves to an array of MeldNodes with location information
* @throws {MeldParseError} If the content cannot be parsed
*/
parseWithLocations(content: string, filePath?: string): Promise<MeldNode[]>;
}
/**
* @package
* Lightweight tracking for variable resolution attempts
*
* Provides tracking capability to monitor variable resolution attempts
* with minimal performance impact when disabled
*/
/**
* Resolution attempt information
*/
interface ResolutionAttempt {
variableName: string;
context: string;
timestamp: number;
success: boolean;
value?: any;
source?: string;
contextBoundary?: {
type: 'parent-to-child' | 'child-to-parent';
sourceId?: string;
targetId?: string;
};
}
/**
* Variable resolution tracking configuration
*/
interface ResolutionTrackingConfig {
enabled: boolean;
samplingRate?: number;
maxAttempts?: number;
watchVariables?: string[];
}
/**
* Tracks variable resolution attempts with minimal performance impact when disabled
*/
declare class VariableResolutionTracker {
private config;
private attempts;
/**
* Enables or disables tracking
*/
configure(config: Partial<ResolutionTrackingConfig>): void;
/**
* Track a variable resolution attempt with minimal overhead when disabled
*/
trackResolutionAttempt(variableName: string, context: string, success: boolean, value?: any, source?: string, contextBoundary?: {
type: 'parent-to-child' | 'child-to-parent';
sourceId?: string;
targetId?: string;
}): void;
/**
* Get all tracked resolution attempts
*/
getAttempts(): ResolutionAttempt[];
/**
* Get resolution attempts for a specific variable
*/
getAttemptsForVariable(variableName: string): ResolutionAttempt[];
/**
* Clear all tracked attempts
*/
clearAttempts(): void;
/**
* Check if tracking is enabled
*/
isEnabled(): boolean;
}
/**
* Interface matching the StructuredPath expected from meld-spec
*/
interface StructuredPath$2 {
raw: string;
structured: {
segments: string[];
variables?: {
special?: string[];
path?: string[];
};
cwd?: boolean;
};
normalized?: string;
isVariableReference?: boolean;
}
/**
* Context for variable resolution, specifying what types of variables and operations are allowed
*/
interface ResolutionContext {
/** Current file being processed, for error reporting */
currentFilePath?: string;
/** What types of variables are allowed in this context */
allowedVariableTypes: {
text: boolean;
data: boolean;
path: boolean;
command: boolean;
};
/** Path validation rules when resolving paths */
pathValidation?: {
requireAbsolute: boolean;
allowedRoots: string[];
};
/** Whether field access is allowed for data variables */
allowDataFields?: boolean;
/** Whether to throw errors on resolution failures (true) or attempt to recover (false) */
strict?: boolean;
/** The state service to use for variable resolution */
state: IStateService;
}
/**
* Service responsible for resolving variables, commands, and paths in different contexts
*/
interface IResolutionService {
/**
* Resolve text variables ({{var}}) in a string
* Formerly used ${var} syntax, now unified with data variables to use {{var}}
*/
resolveText(text: string, context: ResolutionContext): Promise<string>;
/**
* Resolve data variables and fields (#{data.field}) to their values
*/
resolveData(ref: string, context: ResolutionContext): Promise<any>;
/**
* Resolve path variables ($path) to absolute paths.
* This includes $HOMEPATH/$~ and $PROJECTPATH/$. resolution.
*/
resolvePath(path: string, context: ResolutionContext): Promise<string>;
/**
* Resolve command references ($command(args)) to their results
*/
resolveCommand(cmd: string, args: string[], context: ResolutionContext): Promise<string>;
/**
* Resolve content from a file path
*/
resolveFile(path: string): Promise<string>;
/**
* Resolve raw content nodes, preserving formatting but skipping comments
*/
resolveContent(nodes: MeldNode[], context: ResolutionContext): Promise<string>;
/**
* Resolve any value based on the provided context rules
*/
resolveInContext(value: string | StructuredPath$2, context: ResolutionContext): Promise<string>;
/**
* Validate that resolution is allowed in the given context
*/
validateResolution(value: string | StructuredPath$2, context: ResolutionContext): Promise<void>;
/**
* Extract a section from content by its heading
* @param content The content to extract the section from
* @param section The heading text to search for
* @param fuzzy Optional fuzzy matching threshold (0-1, where 1 is exact match, defaults to 0.7)
*/
extractSection(content: string, section: string, fuzzy?: number): Promise<string>;
/**
* Check for circular variable references
*/
detectCircularReferences(value: string): Promise<void>;
/**
* Enable tracking of variable resolution attempts
* @param config Configuration for the resolution tracker
*/
enableResolutionTracking(config: Partial<ResolutionTrackingConfig>): void;
/**
* Get the resolution tracker for debugging
* @returns The current resolution tracker or undefined if not enabled
*/
getResolutionTracker(): VariableResolutionTracker | undefined;
}
declare class ParserService implements IParserService {
private resolutionService?;
constructor(resolutionService?: IResolutionService);
setResolutionService(resolutionService: IResolutionService): void;
private parseContent;
parse(content: string, filePath?: string): Promise<MeldNode[]>;
parseWithLocations(content: string, filePath?: string): Promise<MeldNode[]>;
private isParseError;
private validateCodeFences;
/**
* Transform a variable node to its resolved value
* Used for preview and transformation mode to resolve values
* @param node The node to transform
* @param state The state service to use for lookup
* @returns A text node with the resolved value if transformation is enabled
*/
transformVariableNode(node: MeldNode, state: IStateService): Promise<MeldNode>;
}
/**
* Command definition with optional configuration
*/
interface CommandDefinition {
readonly command: string;
readonly options?: Readonly<Record<string, unknown>>;
}
declare class StateService implements IStateService {
private stateFactory;
private currentState;
private _isImmutable;
private _transformationEnabled;
private _transformationOptions;
private eventService?;
private trackingService?;
constructor(parentState?: IStateService);
setEventService(eventService: IStateEventService): void;
private emitEvent;
getTextVar(name: string): string | undefined;
setTextVar(name: string, value: string): void;
getAllTextVars(): Map<string, string>;
getLocalTextVars(): Map<string, string>;
getDataVar(name: string): unknown;
setDataVar(name: string, value: unknown): void;
getAllDataVars(): Map<string, unknown>;
getLocalDataVars(): Map<string, unknown>;
getPathVar(name: string): string | undefined;
setPathVar(name: string, value: string): void;
getAllPathVars(): Map<string, string>;
getCommand(name: string): CommandDefinition | undefined;
setCommand(name: string, command: string | CommandDefinition): void;
getAllCommands(): Map<string, CommandDefinition>;
getNodes(): MeldNode[];
getTransformedNodes(): MeldNode[];
setTransformedNodes(nodes: MeldNode[]): void;
addNode(node: MeldNode): void;
transformNode(original: MeldNode, transformed: MeldNode): void;
isTransformationEnabled(): boolean;
/**
* Check if a specific transformation type is enabled
* @param type The transformation type to check (variables, directives, commands, imports)
* @returns Whether the specified transformation type is enabled
*/
shouldTransform(type: keyof TransformationOptions): boolean;
/**
* Enable transformation with specific options
* @param options Options for selective transformation, or true/false for all
*/
enableTransformation(options?: TransformationOptions | boolean): void;
/**
* Get the current transformation options
* @returns The current transformation options
*/
getTransformationOptions(): TransformationOptions;
appendContent(content: string): void;
addImport(path: string): void;
removeImport(path: string): void;
hasImport(path: string): boolean;
getImports(): Set<string>;
getCurrentFilePath(): string | null;
setCurrentFilePath(path: string): void;
/**
* In the immutable state model, any non-empty state is considered to have local changes.
* This is a deliberate design choice - each state represents a complete snapshot,
* so the entire state is considered "changed" from its creation.
*
* @returns Always returns true to indicate the state has changes
*/
hasLocalChanges(): boolean;
/**
* Returns a list of changed elements in the state. In the immutable state model,
* the entire state is considered changed from creation, so this always returns
* ['state'] to indicate the complete state has changed.
*
* This is a deliberate design choice that aligns with the immutable state model
* where each state is a complete snapshot.
*
* @returns Always returns ['state'] to indicate the entire state has changed
*/
getLocalChanges(): string[];
setImmutable(): void;
get isImmutable(): boolean;
createChildState(): IStateService;
mergeChildState(childState: IStateService): void;
clone(): IStateService;
private checkMutable;
/**
* Deep clones a value, handling objects, arrays, Maps, Sets, and circular references.
* @param value The value to clone
* @param seen A WeakMap to track circular references
* @returns A deep clone of the value
*/
private deepCloneValue;
private updateState;
setTrackingService(trackingService: IStateTrackingService): void;
getStateId(): string | undefined;
getCommandOutput(command: string): string | undefined;
hasTransformationSupport(): boolean;
}
/**
* Handles resolution of variable references ({{var}})
* Previously used ${var} for text and #{var} for data, now unified as {{var}}
*/
declare class VariableReferenceResolver {
private readonly stateService;
private readonly resolutionService?;
private readonly parserService?;
private readonly MAX_RESOLUTION_DEPTH;
private readonly MAX_ITERATIONS;
private resolutionTracker?;
constructor(stateService: IStateService, resolutionService?: IResolutionService | undefined, parserService?: IParserService | undefined);
/**
* Set the resolution tracker for debugging
* @internal
*/
setResolutionTracker(tracker: VariableResolutionTracker): void;
/**
* Resolves all variable references in the given text
* @param text Text containing variable references like {{varName}}
* @param context Resolution context
* @returns Resolved text with all variables replaced with their values
*/
resolve(content: string, context: ResolutionContext): Promise<string>;
/**
* Resolves a list of nodes, handling variable references
* @param nodes The nodes to resolve
* @param context The resolution context
* @returns The resolved content
*/
resolveNodes(nodes: MeldNode[], context: ResolutionContext): Promise<string>;
/**
* Extract the actual value from a node, not just its string representation
*/
private getNodeValue;
/**
* Convert a node to string representation
* @deprecated Use getNodeValue instead for actual variable values
*/
private nodeToString;
/**
* Resolve text with variable references
*/
private resolveText;
/**
* Resolves a variable node (TextVar or DataVar)
* @param node The variable node to resolve
* @param context The resolution context
* @param resolutionPath Path to detect circular references
* @returns The resolved value
*/
private resolveVarNode;
/**
* Normalizes a variable node to a common format regardless of node type
*/
private normalizeVarNode;
/**
* Handles the resolution of standard text variables using a simpler approach
* @param text Text containing variable references
* @param context Resolution context
* @returns Text with variables resolved
*/
private resolveSimpleVariables;
/**
* Extract variable nodes from the AST
* @param nodes AST nodes
* @returns Array of variable reference nodes
*/
private extractVariableNodesFromAst;
/**
* Extract references using AST - now properly handles async
*/
private extractReferencesAst;
/**
* Extract references from AST nodes
*/
private extractReferencesFromNodes;
/**
* Extract references from text content (helper method)
*/
private extractReferencesFromText;
/**
* Extract references using regex pattern matching - now delegates to async method
* This is kept for backward compatibility
*/
private extractReferencesRegex;
private getSafeTextVars;
private getSafeDataVars;
private resolveWithAst;
/**
* Check if text contains variable references
*/
private hasVariableReferences;
/**
* Extract variable references from a string - now properly uses parser when available
* @param text The text to search for references
* @returns Array of unique variable names
*/
extractReferences(text: string): string[];
/**
* Extract variable references from text (async version)
* Note: This is needed for proper async handling with the parser.
* @param text Text to extract references from
* @returns Promise resolving to array of variable names
*/
extractReferencesAsync(text: string): Promise<string[]>;
/**
* Debug helper to trace field access resolution
* @param obj The object to access fields on
* @param fields Array of field names to access
* @param context Resolution context
* @returns Detailed debug information about field access
*/
private debugFieldAccess;
/**
* Gets a variable from the state service
* @param name The variable name
* @param context The resolution context
* @returns The variable value
*/
private getVariable;
/**
* Track a variable resolution attempt if tracker is available
* @private
*/
private trackResolutionAttempt;
resolveFieldAccess(variableName: string, fieldPath: string, context: ResolutionContext): Promise<any>;
}
/**
* Interface matching the StructuredPath expected from meld-spec
*/
interface StructuredPath$1 {
raw: string;
structured: {
segments: string[];
variables?: {
special?: string[];
path?: string[];
};
cwd?: boolean;
};
normalized?: string;
}
/**
* Service responsible for resolving variables, commands, and paths in different contexts
*/
declare class ResolutionService implements IResolutionService {
private stateService;
private fileSystemService;
private parserService;
private pathService;
private textResolver;
private dataResolver;
private pathResolver;
private commandResolver;
private contentResolver;
private variableReferenceResolver;
private resolutionTracker?;
constructor(stateService: IStateService, fileSystemService: IFileSystemService, parserService: IParserService, pathService: IPathService);
/**
* Parse a string into AST nodes for resolution
*/
private parseForResolution;
/**
* Resolve text variables in a string
*/
resolveText(text: string, context: ResolutionContext): Promise<string>;
/**
* Resolve data variables and fields
*/
resolveData(ref: string, context: ResolutionContext): Promise<any>;
/**
* Resolve path variables
*/
resolvePath(path: string, context: ResolutionContext): Promise<string>;
/**
* Resolve command references
*/
resolveCommand(cmd: string, args: string[], context: ResolutionContext): Promise<string>;
/**
* Resolve content from a file path
*/
resolveFile(path: string): Promise<string>;
/**
* Resolve raw content nodes, preserving formatting but skipping comments
*/
resolveContent(nodes: MeldNode[], context: ResolutionContext): Promise<string>;
/**
* Resolve any value based on the provided context rules
*/
resolveInContext(value: string | StructuredPath$1, context: ResolutionContext): Promise<string>;
/**
* Resolve variables within a string value
* @internal Used by resolveInContext
*/
private resolveVariables;
/**
* Validate that resolution is allowed in the given context
*/
validateResolution(value: string | StructuredPath$1, context: ResolutionContext): Promise<void>;
/**
* Check for circular variable references
*/
detectCircularReferences(value: string): Promise<void>;
/**
* Extract a section from content by its heading
* @param content The content to extract the section from
* @param heading The heading text to search for
* @param fuzzy Optional fuzzy matching threshold (0-1, where 1 is exact match, defaults to 0.7)
*
* NOTE: This implementation contains workarounds for limitations in the llmxml library.
* See dev/LLMXML-IMPROVEMENTS.md for details about planned improvements to the library
* instead of maintaining these workarounds.
*
* Current workarounds include:
* 1. Manual section extraction when llmxml fails
* 2. Error reporting with available headings
* 3. Configurable fuzzy matching threshold
*/
extractSection(content: string, heading: string, fuzzy?: number): Promise<string>;
/**
* Extract all headings from content for error reporting
* This functionality should ideally be provided by the llmxml library
* @private
* @todo Move this functionality into llmxml
*/
private extractHeadings;
/**
* Manual section extraction as a fallback when llmxml fails
* This is a workaround for limitations in the llmxml library
* @private
* @todo Remove once llmxml reliability is improved
*/
private manualSectionExtraction;
private calculateSimilarity;
private nodesToString;
/**
* Resolve a structured path to an absolute path
* @private
*/
private resolveStructuredPath;
/**
* Get the variable reference resolver
*/
getVariableResolver(): VariableReferenceResolver;
/**
* Enable tracking of variable resolution attempts
* @param config Configuration for the resolution tracker
*/
enableResolutionTracking(config: Partial<ResolutionTrackingConfig>): void;
/**
* Get the resolution tracker for debugging
* @returns The current resolution tracker or undefined if not enabled
*/
getResolutionTracker(): VariableResolutionTracker | undefined;
}
/**
* Service for validating and normalizing paths
*/
declare class PathService implements IPathService {
private fs;
private parser;
private testMode;
private homePath;
private projectPath;
private projectPathResolver;
private projectPathResolved;
constructor();
/**
* Initialize the path service with a file system service
*/
initialize(fileSystem: IFileSystemService, parser?: IParserService): void;
/**
* Enable test mode for path operations
*/
enableTestMode(): void;
/**
* Disable test mode for path operations
*/
disableTestMode(): void;
/**
* Check if test mode is enabled
*/
isTestMode(): boolean;
/**
* Set home path for testing
*/
setHomePath(path: string): void;
/**
* Set project path for testing
*/
setProjectPath(path: string): void;
/**
* Get the home path
*/
getHomePath(): string;
/**
* Get the project path
*/
getProjectPath(): string;
/**
* Resolve the project path using the ProjectPathResolver
*/
resolveProjectPath(): Promise<string>;
/**
* Convert a string path to a structured path using the parser service
* @private
*/
private parsePathToStructured;
/**
* Validate a structured path according to Meld's path rules
* @private
*/
private validateStructuredPath;
/**
* Resolve a structured path to its absolute form
* @private
*/
private resolveStructuredPath;
/**
* Resolve a path to its absolute form
*/
resolvePath(filePath: string | StructuredPath, baseDir?: string): string;
/**
* Synchronous version of validateStructuredPath
* @private
*/
private validateStructuredPathSync;
/**
* Validate a path against a set of constraints
*/
validatePath(filePath: string | StructuredPath, options?: PathOptions): Promise<string>;
/**
* Normalize a path by resolving '..' and '.' segments
*/
normalizePath(filePath: string): string;
/**
* Join multiple path segments together
*/
join(...paths: string[]): string;
/**
* Get the directory name of a path
*/
dirname(pathStr: string): string;
/**
* Get the base name of a path
*/
basename(pathStr: string): string;
/**
* Validate a path string that follows Meld path syntax rules
* This is a convenience method that passes the location information to validatePath
*/
validateMeldPath(path: string, location?: Location): void;
/**
* Normalize a path string (replace backslashes with forward slashes)
*/
normalizePathString(path: string): string;
}
declare enum ErrorSeverity {
Fatal = "fatal",
Recoverable = "recoverable",
Warning = "warning"
}
interface MeldErrorOptions {
cause?: Error;
code?: string;
filePath?: string;
severity?: ErrorSeverity;
context?: any;
}
interface SerializedMeldError {
name: string;
message: string;
code?: string;
filePath?: string;
cause?: string;
severity: ErrorSeverity;
context?: any;
}
/**
* Base class for all Meld errors
*/
declare class MeldError extends Error {
readonly code?: string;
readonly filePath?: string;
private readonly errorCause?;
readonly severity: ErrorSeverity;
readonly context?: any;
constructor(message: string, options?: MeldErrorOptions);
/**
* Custom serialization to avoid circular references and include only essential info
*/
toJSON(): SerializedMeldError;
/**
* Check if this error can be treated as a warning in permissive mode
*/
canBeWarning(): boolean;
/**
* Wrap an unknown error in a MeldError
*/
static wrap(error: unknown, message?: string, severity?: ErrorSeverity): MeldError;
}
interface DirectiveLocation {
line: number;
column: number;
filePath?: string;
}
interface MeldDirectiveErrorOptions {
location?: DirectiveLocation;
code?: string;
cause?: Error;
severity?: ErrorSeverity;
context?: any;
}
declare class MeldDirectiveError extends MeldError {
readonly directiveKind: string;
readonly location?: DirectiveLocation;
constructor(message: string, directiveKind: string, options?: MeldDirectiveErrorOptions);
}
/**
* Error codes for directive failures
*/
declare enum DirectiveErrorCode {
VALIDATION_FAILED = "VALIDATION_FAILED",
RESOLUTION_FAILED = "RESOLUTION_FAILED",
EXECUTION_FAILED = "EXECUTION_FAILED",
HANDLER_NOT_FOUND = "HANDLER_NOT_FOUND",
FILE_NOT_FOUND = "FILE_NOT_FOUND",
CIRCULAR_REFERENCE = "CIRCULAR_REFERENCE",
VARIABLE_NOT_FOUND = "VARIABLE_NOT_FOUND",
STATE_ERROR = "STATE_ERROR",
INVALID_CONTEXT = "INVALID_CONTEXT",
SECTION_NOT_FOUND = "SECTION_NOT_FOUND"
}
/**
* Map of directive error codes to severity levels
*/
declare const ValidationErrorSeverity: Record<DirectiveErrorCode, ErrorSeverity>;
declare class ValidationService implements IValidationService {
private validators;
constructor();
/**
* Validate a directive node against its schema and constraints
* @throws {MeldDirectiveError} If validation fails
*/
validate(node: DirectiveNode): Promise<void>;
/**
* Register a validator for a directive kind
*/
registerValidator(kind: string, validator: (node: DirectiveNode) => Promise<void>): void;
/**
* Remove a validator for a directive kind
*/
removeValidator(kind: string): void;
/**
* Check if a validator exists for a directive kind
*/
hasValidator(kind: string): boolean;
/**
* Get all registered directive kinds
*/
getRegisteredDirectiveKinds(): string[];
}
/**
* Service for tracking and detecting circular imports in Meld files.
*/
interface ICircularityService {
/**
* Called at the start of an import operation.
* @throws {MeldImportError} If a circular import is detected
*/
beginImport(filePath: string): void;
/**
* Called after import is finished (success or failure).
* Removes filePath from the import stack.
*/
endImport(filePath: string): void;
/**
* Check if a file is currently in the import stack.
*/
isInStack(filePath: string): boolean;
/**
* Get the current import stack.
*/
getImportStack(): string[];
/**
* Clear the import stack.
*/
reset(): void;
}
declare class CircularityService implements ICircularityService {
private importStack;
beginImport(filePath: string): void;
endImport(filePath: string): void;
isInStack(filePath: string): boolean;
getImportStack(): string[];
reset(): void;
}
/**
* Result of directive execution
*/
interface DirectiveResult {
/** The updated state after directive execution */
state: IStateService;
/** Optional replacement node for transformation */
replacement?: MeldNode;
}
interface ILogger {
debug: (message: string, ...args: any[]) => void;
info: (message: string, ...args: any[]) => void;
warn: (message: string, ...args: any[]) => void;
error: (message: string, ...args: any[]) => void;
}
declare class MeldLLMXMLError extends Error {
readonly code: string;
readonly details?: any | undefined;
constructor(message: string, code: string, details?: any | undefined);
}
/**
* Service responsible for handling directives
*/
declare class DirectiveService implements IDirectiveService {
private validationService?;
private stateService?;
private pathService?;
private fileSystemService?;
private parserService?;
private interpreterService?;
private circularityService?;
private resolutionService?;
private initialized;
private logger;
private handlers;
constructor(logger?: ILogger);
initialize(validationService: IValidationService, stateService: IStateService, pathService: IPathService, fileSystemService: IFileSystemService, parserService: IParserService, interpreterService: IInterpreterService, circularityService: ICircularityService, resolutionService: IResolutionService): void;
/**
* Register all default directive handlers
*/
registerDefaultHandlers(): void;
/**
* Register a new directive handler
*/
registerHandler(handler: IDirectiveHandler): void;
/**
* Handle a directive node
*/
handleDirective(node: DirectiveNode, context: DirectiveContext): Promise<IStateService>;
/**
* Process multiple directives in sequence
*/
processDirectives(nodes: DirectiveNode[], parentContext?: DirectiveContext): Promise<IStateService>;
/**
* Create execution context for a directive
*/
private createContext;
/**
* Update the interpreter service reference
*/
updateInterpreterService(interpreterService: IInterpreterService): void;
/**
* Check if a handler exists for a directive kind
*/
hasHandler(kind: string): boolean;
/**
* Validate a directive node
*/
validateDirective(node: DirectiveNode): Promise<void>;
/**
* Create a child context for nested directives
*/
createChildContext(parentContext: DirectiveContext, filePath: string): DirectiveContext;
supportsDirective(kind: string): boolean;
getSupportedDirectives(): string[];
private ensureInitialized;
private handleTextDirective;
private handleDataDirective;
private handleImportDirective;
private extractSection;
private calculateSimilarity;
private handleEmbedDirective;
/**
* Process a directive node, validating and executing it
* Values in the directive will already be interpolated by meld-ast
* @returns The updated state after directive execution
* @throws {MeldDirectiveError} If directive processing fails
*/
processDirective(node: DirectiveNode, context: DirectiveContext): Promise<IStateService>;
}
type FormatConverter = (nodes: MeldNode[], state: IStateService, options?: OutputOptions) => Promise<string>;
declare class OutputService implements IOutputService {
private formatters;
private state;
private resolutionService;
canAccessTransformedNodes(): boolean;
constructor();
initialize(state: IStateService, resolutionService?: IResolutionService): void;
convert(nodes: MeldNode[], state: IStateService, format: OutputFormat, options?: OutputOptions): Promise<string>;
registerFormat(format: string, converter: FormatConverter): void;
supportsFormat(format: string): boolean;
getSupportedFormats(): string[];
/**
* Helper method to safely extract string content from various node types
* ensuring proper type safety
*/
private getTextContentFromNode;
private convertToMarkdown;
private convertToXML;
private formatStateVariables;
private nodeToMarkdown;
private nodeToXML;
private codeFenceToMarkdown;
private codeFenceToXML;
private directiveToMarkdown;
private directiveToXML;
}
/**
* @package
* Interface for state visualization service.
*
* @remarks
* Provides visualization capabilities for state hierarchies,
* transitions, relationships, and metrics. Supports multiple
* output formats for different use cases (e.g., debug, analysis).
*/
/**
* Supported visualization formats
*/
type VisualizationFormat = 'mermaid' | 'dot' | 'json';
/**
* Node styling options for visualizations
*/
interface NodeStyle {
shape?: 'box' | 'circle' | 'diamond';
color?: string;
label?: string;
tooltip?: string;
}
/**
* Edge styling options for visualizations
*/
interface EdgeStyle {
style?: 'solid' | 'dashed' | 'dotted';
color?: string;
label?: string;
tooltip?: string;
}
/**
* Configuration for generating visualizations
*/
interface VisualizationConfig {
format: VisualizationFormat;
includeMetadata?: boolean;
includeTimestamps?: boolean;
styleNodes?: (metadata: StateMetadata) => NodeStyle;
styleEdges?: (relationship: StateRelationship) => EdgeStyle;
timeRange?: {
start?: number;
end?: number;
};
}
/**
* Configuration for context visualizations
*/
interface ContextVisualizationConfig extends VisualizationConfig {
includeVars?: boolean;
filterToRelevantVars?: boolean;
highlightBoundaries?: boolean;
includeBoundaryTypes?: boolean;
includeFilePaths?: boolean;
}
/**
* Basic metrics about the state system
*/
interface StateMetrics {
totalStates: number;
statesByType: Record<string, number>;
averageTransformationsPerState: number;
maxTransformationChainLength: number;
averageChildrenPerState: number;
maxTreeDepth: number;
operationFrequency: Record<string, number>;
}
/**
* Core state visualization service interface
*/
interface IStateVisualizationService {
/**
* Generate a hierarchical view of state relationships
* @param rootStateId - The root state to start visualization from
* @param config - Visualization configuration
* @returns Visualization in the specified format
*/
generateHierarchyView(rootStateId: string, config: VisualizationConfig): string;
/**
* Generate a transition diagram showing state transformations
* @param stateId - The state to show transitions for
* @param config - Visualization configuration
* @returns Visualization in the specified format
*/
generateTransitionDiagram(stateId: string, config: VisualizationConfig): string;
/**
* Generate a relationship graph showing state connections
* @param stateIds - The states to include in the graph
* @param config - Visualization configuration
* @returns Visualization in the specified format
*/
generateRelationshipGraph(stateIds: string[], config: VisualizationConfig): string;
/**
* Generate a timeline view of state operations
* @param stateIds - The states to include in the timeline
* @param config - Visualization configuration
* @returns Visualization in the specified format
*/
generateTimeline(stateIds: string[], config: VisualizationConfig): string;
/**
* Calculate and return metrics about the state system
* @param timeRange - Optional time range to limit metrics to
* @returns Object containing various metrics
*/
getMetrics(timeRange?: {
start: number;
end: number;
}): StateMetrics;
/**
* Export the complete state graph in the specified format
* @param config - Visualization configuration
* @returns Complete state graph visualization
*/
exportStateGraph(config: VisualizationConfig): string;
/**
* Generate a context hierarchy visualization showing context boundaries
* @param rootStateId - The root state to start visualization from
* @param config - Context visualization configuration
* @returns Context hierarchy visualization in the specified format
*/
visualizeContextHierarchy(rootStateId: string, config: ContextVisualizationConfig): string;
/**
* Generate a variable propagation visualization showing how variables move across contexts
* @param variableName - The name of the variable to track propagation for
* @param rootStateId - Optional root state to limit visualization scope
* @param config - Context visualization configuration
* @returns Variable propagation visualization in the specified format
*/
visualizeVariablePropagation(variableName: string, rootStateId?: string, config?: ContextVisualizationConfig): string;
/**
* Generate a combined context and variable flow visualization
* @param rootStateId - The root state to start visualization from
* @param config - Context visualization configuration
* @returns Combined context and variable flow visualization
*/
visualizeContextsAndVariableFlow(rootStateId: string, config: ContextVisualizationConfig): string;
/**
* Generate a resolution path timeline visualization for a specific variable
* @p