d25d482dc2
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
533 lines
19 KiB
TypeScript
533 lines
19 KiB
TypeScript
/**
|
|
* @vitest-environment node
|
|
*/
|
|
|
|
import { describe, expect, it } from 'vitest'
|
|
import { TextChunker } from './text-chunker'
|
|
|
|
describe('TextChunker', () => {
|
|
describe('basic chunking', () => {
|
|
it.concurrent('should return empty array for empty text', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const chunks = await chunker.chunk('')
|
|
expect(chunks).toEqual([])
|
|
})
|
|
|
|
it.concurrent('should return empty array for whitespace-only text', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const chunks = await chunker.chunk(' \n\n ')
|
|
expect(chunks).toEqual([])
|
|
})
|
|
|
|
it.concurrent('should return single chunk for small text', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'This is a short text.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks).toHaveLength(1)
|
|
expect(chunks[0].text).toBe(text)
|
|
})
|
|
|
|
it.concurrent('should include token count in chunk metadata', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'Hello world'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks[0].tokenCount).toBe(3)
|
|
})
|
|
})
|
|
|
|
describe('chunk size limits (tokens)', () => {
|
|
it.concurrent('should split text that exceeds chunk size', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 50 })
|
|
const text = 'This is a test sentence. '.repeat(20)
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(1)
|
|
})
|
|
|
|
it.concurrent('should respect chunk size limit', async () => {
|
|
const chunkSize = 50
|
|
const chunker = new TextChunker({ chunkSize })
|
|
const text = 'This is a test sentence. '.repeat(20)
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
for (const chunk of chunks) {
|
|
expect(chunk.tokenCount).toBeLessThanOrEqual(chunkSize + 5)
|
|
}
|
|
})
|
|
|
|
it.concurrent('should create more chunks with smaller chunk size', async () => {
|
|
const text = 'This is a test sentence. '.repeat(20)
|
|
|
|
const largeChunker = new TextChunker({ chunkSize: 200 })
|
|
const smallChunker = new TextChunker({ chunkSize: 50 })
|
|
|
|
const largeChunks = await largeChunker.chunk(text)
|
|
const smallChunks = await smallChunker.chunk(text)
|
|
|
|
expect(smallChunks.length).toBeGreaterThan(largeChunks.length)
|
|
})
|
|
})
|
|
|
|
describe('overlap (tokens)', () => {
|
|
it.concurrent('should not add overlap when overlap is 0', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 20, chunkOverlap: 0 })
|
|
const text = 'First sentence here. Second sentence here. Third sentence here.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
if (chunks.length > 1) {
|
|
const firstChunkEnd = chunks[0].text.slice(-10)
|
|
const secondChunkStart = chunks[1].text.slice(0, 10)
|
|
expect(chunks[1].text.startsWith(firstChunkEnd)).toBe(false)
|
|
}
|
|
})
|
|
|
|
it.concurrent('should add overlap from previous chunk', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 20, chunkOverlap: 50 })
|
|
const text =
|
|
'First paragraph with some content here.\n\nSecond paragraph with different content here.\n\nThird paragraph with more content.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
if (chunks.length > 1) {
|
|
expect(chunks[1].text.length).toBeGreaterThan(0)
|
|
}
|
|
})
|
|
|
|
it.concurrent('should handle overlap larger than previous chunk', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 10, chunkOverlap: 500 })
|
|
const text = 'Short. Another short.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
})
|
|
|
|
describe('hierarchical splitting', () => {
|
|
it.concurrent('should prefer splitting on paragraph boundaries', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 30 })
|
|
const text =
|
|
'First paragraph content here.\n\nSecond paragraph content here.\n\nThird paragraph content here.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThanOrEqual(1)
|
|
})
|
|
|
|
it.concurrent('should split on sentences when paragraphs are too large', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 20 })
|
|
const text =
|
|
'First sentence. Second sentence. Third sentence. Fourth sentence. Fifth sentence.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(1)
|
|
})
|
|
|
|
it.concurrent('should split on words as last resort', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 5 })
|
|
const text = 'Supercalifragilisticexpialidocious is a very long word that needs splitting.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(1)
|
|
})
|
|
|
|
it.concurrent('should handle markdown headings', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 30 })
|
|
const text =
|
|
'# Heading 1\n\nContent under heading 1.\n\n## Heading 2\n\nContent under heading 2.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThanOrEqual(1)
|
|
})
|
|
})
|
|
|
|
describe('text cleaning', () => {
|
|
it.concurrent('should normalize Windows line endings', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'Line 1\r\nLine 2\r\nLine 3'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks[0].text).not.toContain('\r')
|
|
})
|
|
|
|
it.concurrent('should collapse multiple spaces', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'Word1 Word2 Word3'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks[0].text).not.toContain(' ')
|
|
})
|
|
|
|
it.concurrent('should limit consecutive newlines', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'Para 1\n\n\n\n\nPara 2'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks[0].text).not.toContain('\n\n\n')
|
|
})
|
|
})
|
|
|
|
describe('chunk metadata', () => {
|
|
it.concurrent('should include startIndex and endIndex', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'This is test content.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks[0].metadata.startIndex).toBeDefined()
|
|
expect(chunks[0].metadata.endIndex).toBeDefined()
|
|
expect(chunks[0].metadata.startIndex).toBe(0)
|
|
})
|
|
|
|
it.concurrent('should have sequential indices across chunks', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 20, chunkOverlap: 0 })
|
|
const text = 'First part of text. Second part of text. Third part of text.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
if (chunks.length > 1) {
|
|
for (let i = 1; i < chunks.length; i++) {
|
|
expect(chunks[i].metadata.startIndex).toBeGreaterThanOrEqual(0)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('default values', () => {
|
|
it.concurrent('should use default chunkSize of 1024 tokens', async () => {
|
|
const chunker = new TextChunker({})
|
|
const text = 'Word '.repeat(400)
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks).toHaveLength(1)
|
|
})
|
|
|
|
it.concurrent('should use default minCharactersPerChunk of 100', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 10 })
|
|
const text = 'This is a longer sentence with more content. '.repeat(5)
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it.concurrent('should use default overlap of 0', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 20 })
|
|
const text = 'First sentence here. Second sentence here.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
if (chunks.length > 1) {
|
|
const firstEnd = chunks[0].text.slice(-5)
|
|
expect(chunks[1].text.startsWith(firstEnd)).toBe(false)
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('edge cases', () => {
|
|
it.concurrent('should handle very long text', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'This is a sentence. '.repeat(1000)
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(1)
|
|
const totalLength = chunks.reduce((sum, c) => sum + c.text.length, 0)
|
|
expect(totalLength).toBeGreaterThan(0)
|
|
})
|
|
|
|
it.concurrent('should handle text with only special characters', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = '!@#$%^&*()_+-=[]{}|;:,.<>?'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks).toHaveLength(1)
|
|
expect(chunks[0].text).toBe(text)
|
|
})
|
|
|
|
it.concurrent('should handle unicode text', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = '这是中文测试。日本語テスト。한국어 테스트.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
expect(chunks[0].text).toContain('中文')
|
|
})
|
|
|
|
it.concurrent('should not lose any content during chunking', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 30, chunkOverlap: 0 })
|
|
const originalText =
|
|
'The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs.'
|
|
const chunks = await chunker.chunk(originalText)
|
|
|
|
const allText = chunks.map((c) => c.text).join(' ')
|
|
expect(allText).toContain('quick')
|
|
expect(allText).toContain('fox')
|
|
expect(allText).toContain('lazy')
|
|
expect(allText).toContain('dog')
|
|
})
|
|
})
|
|
|
|
describe('boundary conditions', () => {
|
|
it.concurrent('should handle text exactly at chunk size boundary', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 10 })
|
|
const text = 'A'.repeat(40)
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks).toHaveLength(1)
|
|
expect(chunks[0].tokenCount).toBe(10)
|
|
})
|
|
|
|
it.concurrent('should handle text one token over chunk size', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 10 })
|
|
const text = 'A'.repeat(44)
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThanOrEqual(1)
|
|
})
|
|
|
|
it.concurrent('should handle chunkSize of 1 token', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 1 })
|
|
const text = 'Hello world test'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(1)
|
|
})
|
|
|
|
it.concurrent('should handle overlap equal to half of chunk size', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 20, chunkOverlap: 10 })
|
|
const text = 'First sentence here. Second sentence here. Third sentence here.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it.concurrent('should clamp overlap to max 50% of chunk size', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 20, chunkOverlap: 60 })
|
|
const text = 'First paragraph here.\n\nSecond paragraph here.\n\nThird paragraph here.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it.concurrent('should handle zero minCharactersPerChunk', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 10, minCharactersPerChunk: 0 })
|
|
const text = 'A B C'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
})
|
|
|
|
describe('encoding and special characters', () => {
|
|
it.concurrent('should handle emoji characters', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'Hello 👋 World 🌍! This has emojis 🎉🎊🎈'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks).toHaveLength(1)
|
|
expect(chunks[0].text).toContain('👋')
|
|
expect(chunks[0].text).toContain('🌍')
|
|
})
|
|
|
|
it.concurrent('should handle mixed language text', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'English text. 中文文本。日本語テキスト。한국어 텍스트. العربية'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
expect(chunks[0].text).toContain('English')
|
|
expect(chunks[0].text).toContain('中文')
|
|
expect(chunks[0].text).toContain('日本語')
|
|
})
|
|
|
|
it.concurrent('should handle RTL text (Arabic/Hebrew)', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'مرحبا بالعالم - שלום עולם - Hello World'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
expect(chunks[0].text).toContain('مرحبا')
|
|
expect(chunks[0].text).toContain('שלום')
|
|
})
|
|
|
|
it.concurrent('should handle null characters in text', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'Hello\0World\0Test'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it.concurrent('should handle combining diacritics', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'cafe\u0301 resume\u0301 naive\u0308'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it.concurrent('should handle zero-width characters', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'Hello\u200B\u200C\u200DWorld'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it.concurrent('should handle old Mac line endings (\\r)', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'Line 1\rLine 2\rLine 3'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks[0].text).not.toContain('\r')
|
|
})
|
|
})
|
|
|
|
describe('large inputs', () => {
|
|
it.concurrent('should handle 10,000 word document', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'This is a test sentence with several words. '.repeat(2000)
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(1)
|
|
const totalChars = chunks.reduce((sum, c) => sum + c.text.length, 0)
|
|
expect(totalChars).toBeGreaterThan(0)
|
|
})
|
|
|
|
it.concurrent('should handle 1MB of text', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 500 })
|
|
const text = 'Lorem ipsum dolor sit amet. '.repeat(40000)
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(1)
|
|
})
|
|
|
|
it.concurrent('should handle very long single line', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 50 })
|
|
const text = 'Word'.repeat(10000)
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(1)
|
|
})
|
|
|
|
it.concurrent('should handle many short paragraphs', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = Array(500)
|
|
.fill(0)
|
|
.map((_, i) => `Paragraph ${i}.`)
|
|
.join('\n\n')
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(1)
|
|
})
|
|
})
|
|
|
|
describe('markdown and code handling', () => {
|
|
it.concurrent('should handle code blocks', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 50 })
|
|
const text = `
|
|
# Code Example
|
|
|
|
\`\`\`javascript
|
|
function hello() {
|
|
console.log("Hello World");
|
|
}
|
|
\`\`\`
|
|
|
|
Some explanation text after the code.
|
|
`
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it.concurrent('should handle nested lists', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 50 })
|
|
const text = `
|
|
- Item 1
|
|
- Nested 1.1
|
|
- Nested 1.2
|
|
- Deep nested 1.2.1
|
|
- Item 2
|
|
- Nested 2.1
|
|
`
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it.concurrent('should handle markdown tables', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 50 })
|
|
const text = `
|
|
| Header 1 | Header 2 | Header 3 |
|
|
|----------|----------|----------|
|
|
| Cell 1 | Cell 2 | Cell 3 |
|
|
| Cell 4 | Cell 5 | Cell 6 |
|
|
`
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it.concurrent('should handle inline code', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 100 })
|
|
const text = 'Use `const` for constants and `let` for variables. Call `myFunction()` here.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks[0].text).toContain('`const`')
|
|
})
|
|
})
|
|
|
|
describe('separator hierarchy', () => {
|
|
it.concurrent('should split on horizontal rules', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 30 })
|
|
const text = 'Section 1 content here.\n---\nSection 2 content here.\n---\nSection 3 content.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it.concurrent('should split on question marks', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 20 })
|
|
const text = 'What is this? How does it work? Why is it important? When to use it?'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it.concurrent('should split on exclamation marks', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 20 })
|
|
const text = 'Amazing! Incredible! Fantastic! Wonderful! Great!'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
|
|
it.concurrent('should split on semicolons', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 20 })
|
|
const text = 'First clause; second clause; third clause; fourth clause'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
expect(chunks.length).toBeGreaterThan(0)
|
|
})
|
|
})
|
|
|
|
describe('chunk index accuracy', () => {
|
|
it.concurrent('should have non-negative indices', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 30, chunkOverlap: 10 })
|
|
const text = 'First part. Second part. Third part. Fourth part. Fifth part.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
for (const chunk of chunks) {
|
|
expect(chunk.metadata.startIndex).toBeGreaterThanOrEqual(0)
|
|
expect(chunk.metadata.endIndex).toBeGreaterThanOrEqual(chunk.metadata.startIndex)
|
|
}
|
|
})
|
|
|
|
it.concurrent('should have endIndex greater than or equal to startIndex', async () => {
|
|
const chunker = new TextChunker({ chunkSize: 20 })
|
|
const text = 'Multiple sentences here. Another one here. And another. And more.'
|
|
const chunks = await chunker.chunk(text)
|
|
|
|
for (const chunk of chunks) {
|
|
expect(chunk.metadata.endIndex).toBeGreaterThanOrEqual(chunk.metadata.startIndex)
|
|
}
|
|
})
|
|
})
|
|
})
|