import { test } from 'brittle'
import { writeFileSync, mkdirSync, rmSync, existsSync } from 'fs'
import { join, resolve, dirname } from 'path'
import { fileURLToPath } from 'url'
import { LiveStore } from '../lib/live-store.js'
import { scanStream } from '../lib/scan-stream.js'
import { TreeReducer } from '../lib/reducers/tree-reducer.js'
const HERE = dirname(fileURLToPath(import.meta.url))
const FIXTURE = resolve(HERE, 'fixtures-live')
function setup () {
if (existsSync(FIXTURE)) rmSync(FIXTURE, { recursive: true, force: true })
mkdirSync(FIXTURE, { recursive: true })
writeFileSync(join(FIXTURE, 'package.json'), JSON.stringify({ name: 'fixture-live', version: '0.1.0', main: 'index.js' }))
writeFileSync(join(FIXTURE, 'index.js'), 'export const x = 1\n')
}
async function buildGraph () {
return new Promise((resolveP, reject) => {
const src = scanStream(FIXTURE)
const tree = new TreeReducer().attach(src)
src.once('scan-end', () => resolveP(tree.finalize()))
src.once('error', reject)
})
}
test('live-store: subscribe receives current state on attach', async (t) => {
setup()
const graph = await buildGraph()
const store = new LiveStore(graph, { watch: false })
store.seedFromGraph()
const events = []
store.subscribe(ev => events.push(ev.type))
t.is(events[0], 'scan-start', 'first replayed event is scan-start')
t.ok(events.includes('module-start'), 'module-start replayed')
t.ok(events.includes('file-discovered'), 'file-discovered replayed')
t.ok(events.includes('file-parsed'), 'file-parsed replayed')
t.is(events[events.length - 1], 'scan-end', 'last replayed event is scan-end')
store.stop()
rmSync(FIXTURE, { recursive: true, force: true })
})
test('live-store: late subscribers also get full state', async (t) => {
setup()
const graph = await buildGraph()
const store = new LiveStore(graph, { watch: false })
store.seedFromGraph()
// First subscriber
const first = []
store.subscribe(ev => first.push(ev.type))
// Second subscriber attaches AFTER seeding — must still get the full replay
const second = []
store.subscribe(ev => second.push(ev.type))
t.is(first.length, second.length, 'both subscribers see same number of events')
t.alike(first, second, 'event sequences match')
store.stop()
rmSync(FIXTURE, { recursive: true, force: true })
})
test('live-store: module-start payload uses moduleType not type for JS module flavor', async (t) => {
setup()
const graph = await buildGraph()
const store = new LiveStore(graph, { watch: false })
store.seedFromGraph()
let modStart = null
store.subscribe(ev => {
if (ev.type === 'module-start' && !modStart) modStart = ev
})
t.ok(modStart, 'got module-start event')
t.is(modStart.type, 'module-start', 'event type is preserved (no name collision)')
t.ok('moduleType' in modStart, 'JS module type carried as moduleType field')
store.stop()
rmSync(FIXTURE, { recursive: true, force: true })
})