import { strict as assert } from 'node:assert' import { test } from 'node:test' import { chunkFile, embedText, isLikelyMinified, languageOf, symbolLabel, symbolOf, } from '../lib/chunk.js' const TS = `import { readFile } from 'node:fs/promises' const CACHE = new Map() export function loadConfig(path) { if (CACHE.has(path)) return CACHE.get(path) const value = { path, loaded: true } CACHE.set(path, value) return value } export function clearCache() { CACHE.clear() } export class Store { constructor() { this.rows = [] } add(row) { this.rows.push(row) } } ` /** A module long enough that its declarations cannot all merge into one chunk. */ function bigModule(count = 6, bodyLines = 14) { const parts = [] for (let at = 0; at < count; at += 1) { const body = Array.from({ length: bodyLines }, (_, line) => ` const step_${at}_${line} = compute(${line})`).join('\n') parts.push(`export function handler_${at}(input) {\n${body}\n return input\n}`) } return `${parts.join('\n\n')}\n` } test('languageOf maps known extensions and ignores unknown ones', () => { assert.equal(languageOf('a/b.ts'), 'javascript') assert.equal(languageOf('a/b.PY'), 'python') assert.equal(languageOf('a/b.rs'), 'rust') assert.equal(languageOf('a/b.unknownext'), undefined) assert.equal(languageOf('Makefile'), undefined) }) test('symbolOf reads a declaration name', () => { assert.equal(symbolOf('export function loadConfig(path) {'), 'loadConfig') assert.equal(symbolOf('export class Store {'), 'Store') assert.equal(symbolOf('def compute_total(items):'), 'compute_total') assert.equal(symbolOf('// just a comment'), undefined) }) test('symbolLabel lists merged declarations and caps a long list', () => { assert.equal(symbolLabel([]), undefined) assert.equal(symbolLabel(['a']), 'a') assert.equal(symbolLabel(['a', 'b']), 'a, b') assert.equal(symbolLabel(['a', 'a', 'b']), 'a, b') assert.equal(symbolLabel(['a', 'b', 'c', 'd', 'e', 'f']), 'a, b, c, d +2') }) test('a small file merges into one chunk labelled with every declaration it holds', () => { const { chunks } = chunkFile({ path: 'src/config.ts', content: TS }) assert.equal(chunks.length, 1, 'a 25-line file belongs in a single chunk') // The label must describe the whole chunk, not just its first declaration: // for a small file this label is the module's only description in the index. assert.equal(chunks[0].symbol, 'CACHE, loadConfig, clearCache, Store') assert.equal(chunks[0].startLine, 1) }) test('a larger file splits at declarations, and each chunk is a real source slice', () => { const content = bigModule() const { chunks } = chunkFile({ path: 'src/handlers.ts', content }) assert.ok(chunks.length >= 3, `expected several chunks, got ${chunks.length}`) const lines = content.split('\n') for (const chunk of chunks) { assert.equal(chunk.text, lines.slice(chunk.startLine - 1, chunk.endLine).join('\n')) } assert.equal(chunks[0].startLine, 1) assert.match(chunks[0].symbol, /handler_0/) }) test('chunkFile merges adjacent small declarations instead of emitting fragments', () => { const source = ['export function a() { return 1 }', '', 'export function b() { return 2 }', '', 'export function c() { return 3 }', ''].join('\n') const { chunks } = chunkFile({ path: 'x.ts', content: source, chunkLines: 48 }) assert.equal(chunks.length, 1, 'three one-line functions should merge into one chunk') assert.equal(chunks[0].symbol, 'a, b, c') }) test('chunkFile splits an oversized declaration with overlap', () => { const body = Array.from({ length: 300 }, (_, at) => ` const value_${at} = compute(${at})`).join('\n') const source = `export function huge() {\n${body}\n}\n` const { chunks } = chunkFile({ path: 'x.ts', content: source, maxChunkLines: 80, overlapLines: 8 }) assert.ok(chunks.length > 1, 'a 300-line function must be split') for (const chunk of chunks) { assert.ok(chunk.endLine - chunk.startLine + 1 <= 80, `chunk was ${chunk.endLine - chunk.startLine + 1} lines`) } // Overlap means consecutive chunks share lines, so no boundary is lost. for (let at = 1; at < chunks.length; at += 1) { assert.ok(chunks[at].startLine <= chunks[at - 1].endLine, 'consecutive chunks should overlap') } // Only the piece holding the signature is labelled with the declaration. assert.equal(chunks[0].symbol, 'huge') assert.equal(chunks[1].symbol, undefined) }) test('chunkFile falls back to windows when the language has no anchor set', () => { const source = Array.from({ length: 200 }, (_, at) => `line ${at} of an unknown dialect`).join('\n') const { chunks } = chunkFile({ path: 'thing.weird', content: source, maxChunkLines: 80, overlapLines: 8 }) assert.ok(chunks.length > 1) assert.equal(chunks[0].startLine, 1) assert.equal(chunks[0].symbol, undefined) }) test('chunkFile refuses generated files rather than indexing noise', () => { const minified = `var a=${'x'.repeat(50_000)};` assert.equal(isLikelyMinified(minified), true) const result = chunkFile({ path: 'bundle.js', content: minified }) assert.deepEqual(result.chunks, []) assert.equal(result.skipped, 'generated-or-minified') }) test('chunkFile reports an empty file as empty', () => { const result = chunkFile({ path: 'a.ts', content: ' \n\n' }) assert.deepEqual(result.chunks, []) assert.equal(result.skipped, 'empty') }) test('chunkFile caps chunks per file', () => { const source = Array.from({ length: 400 }, (_, at) => `export function fn_${at}() { return ${at} }`).join('\n') const { chunks, skipped } = chunkFile({ path: 'many.ts', content: source, chunkLines: 2, maxChunkLines: 2, maxChunks: 10 }) assert.equal(chunks.length, 10) assert.equal(skipped, 'chunk-cap-reached') }) test('embedText carries the path, so a question about a name can find it', () => { const text = embedText('src/auth/session.ts', { symbol: 'issueSession', text: 'export function issueSession() {}' }) assert.match(text, /src\/auth\/session\.ts :: issueSession/) assert.match(text, /export function issueSession/) })