chore(LINT-0001) fix lint errors
This commit is contained in:
@@ -299,7 +299,6 @@ describe('LocalCrawler.crawl() — lock file and minified file exclusions', () =
|
||||
'src/index.ts': 'export {};',
|
||||
'dist/vendor.min.js': '!function(e,t){}()'
|
||||
});
|
||||
const result = await crawlRoot();
|
||||
// dist/ is pruned by default — test via shouldIndexFile logic only if .gitignore present
|
||||
// Use a custom path outside ignored dirs:
|
||||
await fs.rm(root, { recursive: true, force: true });
|
||||
|
||||
@@ -266,7 +266,7 @@ describe('Migration — embedding_profiles', () => {
|
||||
const { client } = createTestDb();
|
||||
const row = client
|
||||
.prepare("SELECT * FROM embedding_profiles WHERE id = 'local-default'")
|
||||
.get() as any;
|
||||
.get() as Record<string, unknown>;
|
||||
expect(row).toBeDefined();
|
||||
expect(row.is_default).toBe(1);
|
||||
expect(row.provider_kind).toBe('local-transformers');
|
||||
|
||||
@@ -9,6 +9,19 @@
|
||||
|
||||
import { EmbeddingError, type EmbeddingProvider, type EmbeddingVector } from './provider.js';
|
||||
|
||||
type LocalEmbeddingResult = {
|
||||
data: ArrayLike<number>;
|
||||
};
|
||||
|
||||
type LocalEmbeddingPipeline = (
|
||||
text: string,
|
||||
options: Record<string, unknown>
|
||||
) => Promise<LocalEmbeddingResult>;
|
||||
|
||||
type TransformersModule = {
|
||||
pipeline: (task: string, model: string) => Promise<LocalEmbeddingPipeline>;
|
||||
};
|
||||
|
||||
export class LocalEmbeddingProvider implements EmbeddingProvider {
|
||||
readonly name = 'local';
|
||||
readonly model = 'Xenova/all-MiniLM-L6-v2';
|
||||
@@ -20,13 +33,11 @@ export class LocalEmbeddingProvider implements EmbeddingProvider {
|
||||
|
||||
async embed(texts: string[]): Promise<EmbeddingVector[]> {
|
||||
if (!this.pipeline) {
|
||||
let transformers: { pipeline: Function };
|
||||
let transformers: TransformersModule;
|
||||
try {
|
||||
// Dynamic import — only succeeds when @xenova/transformers is installed.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
transformers = (await import('@xenova/transformers' as any)) as {
|
||||
pipeline: Function;
|
||||
};
|
||||
transformers = (await import('@xenova/transformers' as any)) as TransformersModule;
|
||||
} catch {
|
||||
throw new EmbeddingError(
|
||||
'@xenova/transformers is not installed. Install it to use the local embedding provider.'
|
||||
|
||||
@@ -37,7 +37,8 @@ export class NoopEmbeddingProvider implements EmbeddingProvider {
|
||||
readonly dimensions = 0;
|
||||
readonly model = 'none';
|
||||
|
||||
async embed(_texts: string[]): Promise<EmbeddingVector[]> {
|
||||
async embed(texts: string[]): Promise<EmbeddingVector[]> {
|
||||
void texts;
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import type { EmbeddingProfile } from '../db/schema.js';
|
||||
export type ProviderFactory = (config: Record<string, unknown>) => EmbeddingProvider;
|
||||
|
||||
const PROVIDER_REGISTRY: Record<string, ProviderFactory> = {
|
||||
'local-transformers': (_config) => new LocalEmbeddingProvider(),
|
||||
'local-transformers': () => new LocalEmbeddingProvider(),
|
||||
'openai-compatible': (config) =>
|
||||
new OpenAIEmbeddingProvider({
|
||||
baseUrl: config.baseUrl as string,
|
||||
|
||||
@@ -124,7 +124,7 @@ export class CodeListItemDto {
|
||||
}
|
||||
|
||||
export class CodeSnippetJsonDto {
|
||||
type: 'code' = 'code';
|
||||
readonly type = 'code' as const;
|
||||
title: string | null;
|
||||
description: string | null;
|
||||
language: string | null;
|
||||
@@ -147,7 +147,7 @@ export class CodeSnippetJsonDto {
|
||||
}
|
||||
|
||||
export class InfoSnippetJsonDto {
|
||||
type: 'info' = 'info';
|
||||
readonly type = 'info' as const;
|
||||
text: string;
|
||||
breadcrumb: string | null;
|
||||
pageId: string;
|
||||
|
||||
@@ -32,9 +32,9 @@ export const BOUNDARY_PATTERNS: Record<string, RegExp> = {
|
||||
python: /^(async\s+)?(def|class)\s+\w+/,
|
||||
go: /^(func|type|var|const)\s+\w+/,
|
||||
rust: /^(pub(\s*\(crate\))?\s+)?(async\s+)?(fn|impl|struct|enum|trait|type|const|static)\s+\w+/,
|
||||
java: /^(\s*(public|private|protected|static|final|abstract|synchronized)\s+)+[\w<>\[\]]+\s+\w+\s*[({]/,
|
||||
java: /^(\s*(public|private|protected|static|final|abstract|synchronized)\s+)+[\w<>[\]]+\s+\w+\s*[({]/,
|
||||
csharp:
|
||||
/^(\s*(public|private|protected|internal|static|override|virtual|abstract|sealed)\s+)+[\w<>\[\]]+\s+\w+\s*[({]/,
|
||||
/^(\s*(public|private|protected|internal|static|override|virtual|abstract|sealed)\s+)+[\w<>[\]]+\s+\w+\s*[({]/,
|
||||
kotlin:
|
||||
/^(\s*(public|private|protected|internal|override|suspend|inline|open|abstract|sealed)\s+)*(fun|class|object|interface|data class|sealed class|enum class)\s+\w+/,
|
||||
swift:
|
||||
@@ -111,7 +111,7 @@ function slidingWindowChunks(content: string, filePath: string, language: string
|
||||
* followed by colon/equals/brace) and treat each as a boundary.
|
||||
*/
|
||||
function parseConfigFile(content: string, filePath: string, language: string): RawSnippet[] {
|
||||
const topLevelKey = /^[\w"'\-]+\s*[:=\[{]/;
|
||||
const topLevelKey = /^[\w"'-]+\s*[:=[{]/;
|
||||
const lines = content.split('\n');
|
||||
const segments: string[] = [];
|
||||
let current: string[] = [];
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* - With embeddings : crawl+parse = 80 %, embeddings = 20 %
|
||||
*/
|
||||
|
||||
import { createHash } from 'node:crypto';
|
||||
import { createHash, randomUUID } from 'node:crypto';
|
||||
import type Database from 'better-sqlite3';
|
||||
import type { Document, NewDocument, NewSnippet } from '$lib/types';
|
||||
import type { crawl as GithubCrawlFn } from '$lib/server/crawler/github.crawler.js';
|
||||
@@ -92,7 +92,7 @@ export class IndexingPipeline {
|
||||
this.updateRepo(repo.id, { state: 'indexing' });
|
||||
|
||||
// ---- Stage 1: Crawl -------------------------------------------------
|
||||
const crawlResult = await this.crawl(repo, normJob);
|
||||
const crawlResult = await this.crawl(repo);
|
||||
const totalFiles = crawlResult.totalFiles;
|
||||
|
||||
this.updateJob(job.id, { totalFiles });
|
||||
@@ -140,7 +140,7 @@ export class IndexingPipeline {
|
||||
const checksum = file.sha || sha256(file.content);
|
||||
|
||||
// Create new document record.
|
||||
const documentId = crypto.randomUUID();
|
||||
const documentId = randomUUID();
|
||||
const now = new Date();
|
||||
const newDoc: NewDocument = {
|
||||
id: documentId,
|
||||
@@ -247,10 +247,7 @@ export class IndexingPipeline {
|
||||
// Private — crawl
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private async crawl(
|
||||
repo: Repository,
|
||||
job: IndexingJob
|
||||
): Promise<{
|
||||
private async crawl(repo: Repository): Promise<{
|
||||
files: Array<{ path: string; content: string; sha: string; size: number; language: string }>;
|
||||
totalFiles: number;
|
||||
}> {
|
||||
|
||||
@@ -153,7 +153,7 @@ function makeNoopProvider(): EmbeddingProvider {
|
||||
name: 'noop',
|
||||
dimensions: 0,
|
||||
model: 'none',
|
||||
async embed(_texts: string[]): Promise<EmbeddingVector[]> {
|
||||
async embed(): Promise<EmbeddingVector[]> {
|
||||
return [];
|
||||
},
|
||||
async isAvailable(): Promise<boolean> {
|
||||
@@ -738,7 +738,7 @@ describe('HybridSearchService', () => {
|
||||
const repoId = seedRepo(client);
|
||||
const docId = seedDocument(client, repoId);
|
||||
|
||||
const snippetId = seedSnippet(client, {
|
||||
seedSnippet(client, {
|
||||
repositoryId: repoId,
|
||||
documentId: docId,
|
||||
content: 'keyword only test'
|
||||
@@ -860,7 +860,7 @@ describe('HybridSearchService', () => {
|
||||
it('searchMode=semantic returns empty array for blank query', async () => {
|
||||
const client = createTestDb();
|
||||
const repoId = seedRepo(client);
|
||||
const docId = seedDocument(client, repoId);
|
||||
seedDocument(client, repoId);
|
||||
|
||||
const mockProvider = makeMockProvider([[1, 0, 0, 0]]);
|
||||
|
||||
@@ -879,7 +879,7 @@ describe('HybridSearchService', () => {
|
||||
it('searchMode=semantic falls back to empty when provider fails', async () => {
|
||||
const client = createTestDb();
|
||||
const repoId = seedRepo(client);
|
||||
const docId = seedDocument(client, repoId);
|
||||
seedDocument(client, repoId);
|
||||
|
||||
const noopProvider = makeNoopProvider();
|
||||
const searchService = new SearchService(client);
|
||||
|
||||
@@ -46,8 +46,8 @@ export function preprocessQuery(raw: string): string {
|
||||
.replace(/[()[\]{}]/g, ' ') // Remove grouping characters
|
||||
.replace(/[;:,!?]/g, ' ') // Remove punctuation that breaks FTS
|
||||
.replace(/[<>|]/g, ' ') // Remove comparison/pipe chars
|
||||
.replace(/[\-+*/%]/g, ' ') // Remove operators (but keep underscores)
|
||||
.replace(/[@#$&^\\~\`]/g, ' '); // Remove special chars
|
||||
.replace(/[-+*/%]/g, ' ') // Remove operators (but keep underscores)
|
||||
.replace(/[@#$&^~`\\]/g, ' '); // Remove special chars
|
||||
|
||||
// Split on remaining punctuation (like dots and slashes) but preserve alphanumeric/underscore.
|
||||
const parts = sanitized.split(/[./\s]+/).filter(Boolean);
|
||||
|
||||
@@ -62,21 +62,6 @@ interface RawRepo {
|
||||
updated_at: number;
|
||||
}
|
||||
|
||||
// Raw row shape returned by better-sqlite3 SELECT * FROM indexing_jobs.
|
||||
interface RawJob {
|
||||
id: string;
|
||||
repository_id: string;
|
||||
version_id: string | null;
|
||||
status: string;
|
||||
progress: number;
|
||||
total_files: number;
|
||||
processed_files: number;
|
||||
error: string | null;
|
||||
started_at: number | null;
|
||||
completed_at: number | null;
|
||||
created_at: number;
|
||||
}
|
||||
|
||||
function makeService(client: Database.Database): RepositoryService {
|
||||
return new RepositoryService(client);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* output — the same pattern used by repository.service.test.ts.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import Database from 'better-sqlite3';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
RepositoryVersionEntity
|
||||
} from '$lib/server/models/repository-version.js';
|
||||
import { AlreadyExistsError, NotFoundError } from '$lib/server/utils/validation';
|
||||
import { resolveTagToCommit, discoverVersionTags } from '$lib/server/utils/git.js';
|
||||
|
||||
export class VersionService {
|
||||
constructor(private readonly db: Database.Database) {}
|
||||
@@ -62,7 +63,6 @@ export class VersionService {
|
||||
let resolvedCommitHash = commitHash;
|
||||
if (!resolvedCommitHash && repo.source === 'local') {
|
||||
try {
|
||||
const { resolveTagToCommit } = require('$lib/server/utils/git.js');
|
||||
resolvedCommitHash = resolveTagToCommit({ repoPath: repo.source_url, tag });
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
@@ -178,7 +178,6 @@ export class VersionService {
|
||||
throw new Error('Tag discovery is only supported for local repositories');
|
||||
}
|
||||
|
||||
const { discoverVersionTags, resolveTagToCommit } = require('$lib/server/utils/git.js');
|
||||
const tags = discoverVersionTags({ repoPath: repo.source_url });
|
||||
|
||||
return tags.map((tag: string) => {
|
||||
|
||||
Reference in New Issue
Block a user