import fs from 'fs/promises'; import os from 'os'; import path from 'path'; import { VLProjectContext } from './src/vl/project-context.js'; let passed = 0; let failed = 0; function test(name, fn) { return Promise.resolve() .then(fn) .then(() => { console.log(` ✓ ${name}`); passed++; }) .catch((err) => { console.log(` ✗ ${name}: ${err.message}`); failed++; }); } function assertEqual(actual, expected, msg) { if (actual !== expected) { throw new Error(msg || `Expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`); } } function assert(cond, msg) { if (!cond) throw new Error(msg || 'Assertion failed'); } console.log('\n── Project Context Regression ──'); const tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'vlcode-project-context-')); const populatedDir = path.join(tmpRoot, 'PopulatedProject'); const emptyDir = path.join(tmpRoot, 'EmptyProject'); await fs.mkdir(path.join(populatedDir, 'Apps'), { recursive: true }); await fs.mkdir(path.join(populatedDir, '.vl-code', 'rules'), { recursive: true }); await fs.mkdir(path.join(emptyDir, 'Theme'), { recursive: true }); await fs.mkdir(path.join(emptyDir, '.vl-code'), { recursive: true }); await fs.writeFile( path.join(populatedDir, 'Apps', 'OrdersApp.vx'), '// VL_VERSION:3.5\n\n', 'utf8' ); await fs.writeFile( path.join(populatedDir, '.vl-code', 'rules', 'naming.md'), '# naming rule\n', 'utf8' ); await fs.writeFile( path.join(emptyDir, 'Theme', 'Theme.vth'), '// VL_VERSION:3.5\n\n', 'utf8' ); await fs.writeFile( path.join(emptyDir, '.vl-code', 'ProjectMeta.json'), JSON.stringify({ projectName: 'EmptyProject' }, null, 2), 'utf8' ); await test('load resets stale project identity when switching workspaces', async () => { const ctx = new VLProjectContext(populatedDir); await ctx.load(); assertEqual(ctx.getSummary()?.projectName, 'Orders'); assert(ctx.getRules().length > 0, 'expected rules from populated project'); ctx.workDir = emptyDir; await ctx.load(); assertEqual(ctx.getSummary()?.projectName, null, 'projectName should reset when new workspace has no app/db'); assertEqual(ctx.getRules().length, 0, 'rules should reset when switching workspaces'); assertEqual(ctx.getAllFiles().some((f) => f.path === 'Apps/OrdersApp.vx'), false, 'previous files should not persist'); }); await test('ProjectMeta projectName overrides generic database file names', async () => { const metaNamedDir = path.join(tmpRoot, 'MetaNamedProject'); await fs.mkdir(path.join(metaNamedDir, 'Apps'), { recursive: true }); await fs.mkdir(path.join(metaNamedDir, 'Database'), { recursive: true }); await fs.mkdir(path.join(metaNamedDir, '.vl-code'), { recursive: true }); await fs.writeFile( path.join(metaNamedDir, 'Apps', 'TodoApp.vx'), '// VL_VERSION:3.5\n\n', 'utf8' ); await fs.writeFile( path.join(metaNamedDir, 'Database', 'main.vdb'), '// VL_VERSION:3.5\n\n', 'utf8' ); await fs.writeFile( path.join(metaNamedDir, '.vl-code', 'ProjectMeta.json'), JSON.stringify({ projectName: 'TodoTest', apps: [{ name: 'TodoApp', filePath: 'Apps/TodoApp.vx' }], }, null, 2), 'utf8' ); const ctx = new VLProjectContext(metaNamedDir); await ctx.load(); assertEqual(ctx.getSummary()?.projectName, 'TodoTest'); }); console.log(`\n── Results ──\n\n ${passed} passed, ${failed} failed\n`); process.exit(failed > 0 ? 1 : 0);