Project Files
src / sampler.ts
/**
* @file sampler.ts
* @description Main sampling logic. Routes to the correct strategy implementation
* based on the configured strategy type. Handles edge cases: empty text,
* invalid chunkSize, negative overlap.
*/
import type { SamplingConfig, SampleResult } from "./types";
import { sampleByLength } from "./strategies/length";
import { sampleByPriority } from "./strategies/priority";
import { sampleByRelevance } from "./strategies/relevance";
// ---------------------------------------------------------------------------
// Strategy router
// ---------------------------------------------------------------------------
/**
* Sample text using the configured strategy.
*
* Routing:
* - "length" → sampleByLength: fixed-size chunking, document order
* - "priority" → sampleByPriority: keyword-frequency + position scoring
* - "relevance" → sampleByRelevance: BM25-style query scoring
*
* Edge cases handled:
* - Empty text → returns empty chunks array
* - chunkSize < 1 → clamped to 1
* - Negative overlap → clamped to 0
* - maxChunks ≤ 0 → treated as unlimited
*
* @param text - The input text to sample.
* @param config - Sampling configuration including strategy selector.
* @returns A SampleResult with the sampled chunks and metadata.
*/
export function sample(text: string, config: SamplingConfig): SampleResult {
// Normalise config edge cases
const normalised: SamplingConfig = {
...config,
chunkSize:
config.chunkSize != null ? Math.max(1, config.chunkSize) : undefined,
overlap: config.overlap != null ? Math.max(0, config.overlap) : undefined,
maxChunks:
config.maxChunks != null && config.maxChunks > 0
? config.maxChunks
: undefined,
};
const originalLength = text.length;
// Empty text edge case
if (text.length === 0) {
return {
chunks: [],
totalChunks: 0,
originalLength: 0,
strategy: config.strategy,
};
}
let chunks: readonly import("./types").Chunk[];
switch (config.strategy) {
case "length": {
chunks = sampleByLength(text, normalised);
break;
}
case "priority": {
chunks = sampleByPriority(text, normalised);
break;
}
case "relevance": {
chunks = sampleByRelevance(text, normalised);
break;
}
default: {
// Exhaustiveness check: if a new strategy is added to the type but not
// handled here, TypeScript will flag this line.
const _exhaustive: never = config.strategy;
throw new Error(`Unknown sampling strategy: ${_exhaustive}`);
}
}
return {
chunks,
totalChunks: chunks.length,
originalLength,
strategy: config.strategy,
};
}