init
This commit is contained in:
commit
0964819cdc
34 files changed
+7912
No files matched your search
@@ -0,0 +1,150 @@
|
||||
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/)
|
||||
})
|
||||
Reference in new issue
Block a user