import { vi, beforeEach } from 'vitest'; import type { DirectiveNode, MeldNode } from 'meld-spec'; import { InterpreterState } from '../../_old/src/interpreter/state/state.js'; import { ErrorFactory } from '../../_old/src/interpreter/errors/factory.js'; import { HandlerContext } from '../../_old/src/interpreter/directives/types.js'; import { embedDirectiveHandler, importDirectiveHandler } from './directive-handlers.js'; // Mock file system state const mockFiles: Record = {}; // Mock file management functions function getMockFiles(): Record { return mockFiles; } export function addMockFile(path: string, content: string) { mockFiles[path] = content; } export function clearMockFiles() { Object.keys(mockFiles).forEach(key => delete mockFiles[key]); } // Mock fs module vi.mock('fs', () => ({ default: { readFileSync: vi.fn((path: string) => { if (mockFiles[path]) { return mockFiles[path]; } throw new Error(`ENOENT: no such file or directory, open '${path}'`); }), writeFileSync: vi.fn((path: string, content: string) => { mockFiles[path] = content; }), existsSync: vi.fn((path: string) => !!mockFiles[path]), mkdirSync: vi.fn(), promises: { readFile: vi.fn(async (path: string) => { if (mockFiles[path]) { return mockFiles[path]; } throw new Error(`ENOENT: no such file or directory, open '${path}'`); }), writeFile: vi.fn(async (path: string, content: string) => { mockFiles[path] = content; }) } }, readFileSync: vi.fn((path: string) => { if (mockFiles[path]) { return mockFiles[path]; } throw new Error(`ENOENT: no such file or directory, open '${path}'`); }), writeFileSync: vi.fn((path: string, content: string) => { mockFiles[path] = content; }), existsSync: vi.fn((path: string) => !!mockFiles[path]), mkdirSync: vi.fn(), promises: { readFile: vi.fn(async (path: string) => { if (mockFiles[path]) { return mockFiles[path]; } throw new Error(`ENOENT: no such file or directory, open '${path}'`); }), writeFile: vi.fn(async (path: string, content: string) => { mockFiles[path] = content; }) } })); // Mock path module vi.mock('path', async () => { // Import the path mock factory const { createPathMock } = await import('./path'); // Create a single mock instance that will be used for both named and default exports const mockExports = await createPathMock(); // Return the mock exports directly - they already include __esModule and default return mockExports; }); // Mock InterpreterState with enhanced tracking export class MockInterpreterState extends InterpreterState { private nodeHistory: MeldNode[] = []; private textVarHistory: Map = new Map(); private dataVarHistory: Map = new Map(); constructor() { super(); } // Track node history override addNode(node: MeldNode): void { this.nodeHistory.push({ ...node }); super.addNode(node); } getNodeHistory(): MeldNode[] { return [...this.nodeHistory]; } // Track text var history override setTextVar(name: string, value: string): void { const history = this.textVarHistory.get(name) || []; history.push(value); this.textVarHistory.set(name, history); super.setTextVar(name, value); } getTextVarHistory(name: string): string[] { return this.textVarHistory.get(name) || []; } // Track data var history override setDataVar(name: string, value: any): void { const history = this.dataVarHistory.get(name) || []; history.push(value); this.dataVarHistory.set(name, history); super.setDataVar(name, value); } getDataVarHistory(name: string): any[] { return this.dataVarHistory.get(name) || []; } // Clear history clearHistory(): void { this.nodeHistory = []; this.textVarHistory.clear(); this.dataVarHistory.clear(); } // Existing methods with proper error handling override mergeChildState(childState: InterpreterState): void { try { super.mergeChildState(childState); } catch (error) { throw ErrorFactory.createInterpretError( `Failed to merge child state: ${error instanceof Error ? error.message : String(error)}`, 'State' ); } } } // Mock handler factory with enhanced error handling function createMockHandler(kind: string) { const handlers: Record = { data: { canHandle: (k: string) => k === 'data', handle: async (node: DirectiveNode, state: InterpreterState, context: HandlerContext) => { const data = node.directive; if (!data.name) { throw ErrorFactory.createDirectiveError( 'Data directive requires a name', 'data', node.location?.start ); } state.setDataVar(data.name, data.value); } }, text: { canHandle: (k: string) => k === 'text', handle: async (node: DirectiveNode, state: InterpreterState, context: HandlerContext) => { const data = node.directive; if (!data.name) { throw ErrorFactory.createDirectiveError( 'Text directive requires a name', 'text', node.location?.start ); } state.setTextVar(data.name, data.value); } }, run: { canHandle: (k: string) => k === 'run', handle: async (node: DirectiveNode, state: InterpreterState, context: HandlerContext) => { const data = node.directive; if (!data.command) { throw ErrorFactory.createDirectiveError( 'Run directive requires a command', 'run', node.location?.start ); } const commandData = state.getCommand(data.command); if (commandData && typeof commandData === 'object' && 'command' in commandData) { const { command } = commandData as { command: string }; console.log(`[MOCK] Executing command: ${command}`); } } }, define: { canHandle: (k: string) => k === 'define', handle: async (node: DirectiveNode, state: InterpreterState, context: HandlerContext) => { const data = node.directive; if (!data.name) { throw ErrorFactory.createDirectiveError( 'Define directive requires a name', 'define', node.location?.start ); } state.setCommand(data.name, data.command || ''); } } }; return handlers[kind]; } // File system utilities export function mockFile(path: string, content: string): void { mockFiles[path] = content; } // Add test fixtures beforeEach(() => { clearMockFiles(); // Basic fixtures addMockFile('/Users/adam/dev/meld/src/__fixtures__/markdown/basic.md', ` # Basic Document ## Section One Some content in section one ## Section Two Some content in section two ### Nested Section This is a nested section \`\`\`typescript function test() { console.log('Hello'); } \`\`\` `); addMockFile('/Users/adam/dev/meld/src/__fixtures__/xml/expected/basic.xml', `
Some content in section one
Some content in section two
This is a nested section\`\`\`typescript function test() { console.log('Hello'); } \`\`\`
`); // Complex fixtures addMockFile('/Users/adam/dev/meld/src/__fixtures__/markdown/complex.md', ` # Complex Document ## 你好,世界 Some unicode content ## 🎉 Emoji Title 🚀 こんにちは and Café ## Code Blocks \`\`\`typescript interface Test { name: string; } \`\`\` \`\`\`python def hello(): print("Hello") \`\`\` ## About the Project Project info ### About Development Dev info ## Getting Started (Quick Guide) This section has a title with parentheses `); addMockFile('/Users/adam/dev/meld/src/__fixtures__/xml/expected/complex.xml', `
Some unicode content
こんにちは and Café
\`\`\`typescript interface Test { name: string; } \`\`\` \`\`\`python def hello(): print("Hello") \`\`\`
Project info
Dev info
This section has a title with parentheses
`); // Edge cases addMockFile('/Users/adam/dev/meld/src/__fixtures__/markdown/edge-cases.md', ` # Edge Cases ## Malformed Code Block \`\`\`typescript const x = { // Missing closing brace ## Incomplete Code Fence \`\`\`python def test(): print("No closing fence") ## Empty Section ## HTML in Markdown

Raw HTML header

Some content
`); // Real-world examples addMockFile('/Users/adam/dev/meld/src/__fixtures__/real-world/architecture.md', ` # Architecture Documentation ## System Overview The system consists of multiple components: - Frontend - Backend - Database ## Component Details ### Frontend Built with React & TypeScript ### Backend Node.js with Express ### Database PostgreSQL for persistence ## Deployment Using Docker & Kubernetes `); addMockFile('/Users/adam/dev/meld/src/__fixtures__/xml/expected/real-world/architecture.xml', `
The system consists of multiple components: - Frontend - Backend - Database
Built with React & TypeScript
Node.js with Express
PostgreSQL for persistence
Using Docker & Kubernetes
`); }); // Export utilities export { createMockHandler, mockFiles };