import { test } from 'brittle'
import { resolve, dirname } from 'path'
import { fileURLToPath } from 'url'
import { scan } from '../lib/scanner.js'
import {
parseLocation, locationToUrl, otherSurface, splitFilePath, joinFilePath
} from '../lib/floor/location.js'
const HERE = dirname(fileURLToPath(import.meta.url))
const WORKSPACE = resolve(HERE, 'fixtures/workspace')
// One location model for both surfaces. The SPA's PATH scheme is canonical
// because it is the one with existing deep links; the floor adopts it under a
// /floor prefix and the symbol rung extends it.
test('location: the canonical SPA scheme round-trips', (t) => {
const cases = [
['/', { surface: 'spa', kind: 'system' }],
['/module/hyper-overlay', { surface: 'spa', kind: 'module', module: 'hyper-overlay' }],
['/module/hyper-overlay/file/lib/tree.js',
{ surface: 'spa', kind: 'file', module: 'hyper-overlay', file: 'lib/tree.js' }],
['/path/hyper-fleeky/codetree', { surface: 'spa', kind: 'path', path: ['hyper-fleeky', 'codetree'] }]
]
for (const [url, expected] of cases) {
const loc = parseLocation(url)
for (const k of Object.keys(expected)) t.alike(loc[k], expected[k], url + ' -> ' + k)
t.is(locationToUrl(loc), url, url + ' round-trips')
}
})
test('location: the symbol rung extends the same scheme', (t) => {
const url = '/module/codetree/file/lib/floor/cards.js/symbol/buildFileLevel'
const loc = parseLocation(url)
t.is(loc.kind, 'symbol', 'a symbol location')
t.is(loc.module, 'codetree', 'module')
t.is(loc.file, 'lib/floor/cards.js', 'the file path keeps its own slashes')
t.is(loc.symbol, 'buildFileLevel', 'symbol')
t.is(locationToUrl(loc), url, 'round-trips')
})
test('location: the floor is the same place under a prefix', (t) => {
const spa = parseLocation('/module/codetree/file/index.js')
const floor = parseLocation('/floor/module/codetree/file/index.js')
t.is(floor.surface, 'floor', 'surface is read from the prefix')
t.is(spa.surface, 'spa', 'and defaults to the SPA')
for (const k of ['kind', 'module', 'file', 'symbol']) {
t.alike(floor[k], spa[k], 'same ' + k)
}
t.is(locationToUrl(floor), '/floor/module/codetree/file/index.js', 'round-trips with the prefix')
})
test('location: otherSurface is the same place on the other view', (t) => {
const loc = parseLocation('/module/codetree/file/lib/layout.js')
t.is(otherSurface(loc), '/floor/module/codetree/file/lib/layout.js', 'spa -> floor')
const back = parseLocation(otherSurface(loc))
t.is(otherSurface(back), '/module/codetree/file/lib/layout.js', 'floor -> spa')
t.alike({ ...back, surface: 'spa' }, loc, 'and nothing else changes')
})
test('location: a base prefix is honoured on the way in and out', (t) => {
const loc = parseLocation('/codetree/module/x', '/codetree')
t.is(loc.kind, 'module', 'parsed under the prefix')
t.is(locationToUrl(loc, '/codetree'), '/codetree/module/x', 'and written back with it')
})
test('location: the SPA-only views survive', (t) => {
t.is(parseLocation('/validation').kind, 'validation', 'validation')
t.is(parseLocation('/validation/module/x').extra.moduleName, 'x', 'with its module')
t.is(parseLocation('/docs/spec/SYSTEM.md').extra.docPath, 'spec/SYSTEM.md', 'docs path')
t.is(locationToUrl(parseLocation('/docs/spec/SYSTEM.md')), '/docs/spec/SYSTEM.md', 'round-trips')
t.is(parseLocation('/suggestions/spec/x.md').kind, 'suggestions', 'suggestions')
})
test('location: nonsense is the system level, not a throw', (t) => {
for (const url of ['', '/nope', '/module', '/module//file//', '///']) {
const loc = parseLocation(url)
t.ok(loc.kind, url + ' parses to something: ' + loc.kind)
}
})
test('location: a root-relative path splits into module + file, and back', async (t) => {
const tree = await scan(WORKSPACE, { maxDepth: 1 })
const split = splitFilePath(tree, 'widget-store/lib/widget-store.js')
t.is(split.module, 'widget-store', 'module found')
t.is(split.file, 'lib/widget-store.js', 'path within it')
t.is(joinFilePath(tree, split.module, split.file), 'widget-store/lib/widget-store.js', 'and back')
t.alike(splitFilePath(tree, 'nope/nothing.js'), { module: null, file: null }, 'unknown is null')
})