@mhalder/qdrant-mcp-server 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codecov.yml +16 -0
- package/CHANGELOG.md +18 -0
- package/README.md +236 -9
- package/build/code/chunker/base.d.ts +19 -0
- package/build/code/chunker/base.d.ts.map +1 -0
- package/build/code/chunker/base.js +5 -0
- package/build/code/chunker/base.js.map +1 -0
- package/build/code/chunker/character-chunker.d.ts +22 -0
- package/build/code/chunker/character-chunker.d.ts.map +1 -0
- package/build/code/chunker/character-chunker.js +111 -0
- package/build/code/chunker/character-chunker.js.map +1 -0
- package/build/code/chunker/tree-sitter-chunker.d.ts +29 -0
- package/build/code/chunker/tree-sitter-chunker.d.ts.map +1 -0
- package/build/code/chunker/tree-sitter-chunker.js +213 -0
- package/build/code/chunker/tree-sitter-chunker.js.map +1 -0
- package/build/code/config.d.ts +11 -0
- package/build/code/config.d.ts.map +1 -0
- package/build/code/config.js +145 -0
- package/build/code/config.js.map +1 -0
- package/build/code/indexer.d.ts +42 -0
- package/build/code/indexer.d.ts.map +1 -0
- package/build/code/indexer.js +508 -0
- package/build/code/indexer.js.map +1 -0
- package/build/code/metadata.d.ts +32 -0
- package/build/code/metadata.d.ts.map +1 -0
- package/build/code/metadata.js +128 -0
- package/build/code/metadata.js.map +1 -0
- package/build/code/scanner.d.ts +35 -0
- package/build/code/scanner.d.ts.map +1 -0
- package/build/code/scanner.js +108 -0
- package/build/code/scanner.js.map +1 -0
- package/build/code/sync/merkle.d.ts +45 -0
- package/build/code/sync/merkle.d.ts.map +1 -0
- package/build/code/sync/merkle.js +116 -0
- package/build/code/sync/merkle.js.map +1 -0
- package/build/code/sync/snapshot.d.ts +41 -0
- package/build/code/sync/snapshot.d.ts.map +1 -0
- package/build/code/sync/snapshot.js +91 -0
- package/build/code/sync/snapshot.js.map +1 -0
- package/build/code/sync/synchronizer.d.ts +53 -0
- package/build/code/sync/synchronizer.d.ts.map +1 -0
- package/build/code/sync/synchronizer.js +132 -0
- package/build/code/sync/synchronizer.js.map +1 -0
- package/build/code/types.d.ts +98 -0
- package/build/code/types.d.ts.map +1 -0
- package/build/code/types.js +5 -0
- package/build/code/types.js.map +1 -0
- package/build/index.js +250 -0
- package/build/index.js.map +1 -1
- package/examples/code-search/README.md +271 -0
- package/package.json +13 -1
- package/src/code/chunker/base.ts +22 -0
- package/src/code/chunker/character-chunker.ts +131 -0
- package/src/code/chunker/tree-sitter-chunker.ts +250 -0
- package/src/code/config.ts +156 -0
- package/src/code/indexer.ts +613 -0
- package/src/code/metadata.ts +153 -0
- package/src/code/scanner.ts +124 -0
- package/src/code/sync/merkle.ts +136 -0
- package/src/code/sync/snapshot.ts +110 -0
- package/src/code/sync/synchronizer.ts +154 -0
- package/src/code/types.ts +117 -0
- package/src/index.ts +296 -0
- package/tests/code/chunker/character-chunker.test.ts +141 -0
- package/tests/code/chunker/tree-sitter-chunker.test.ts +275 -0
- package/tests/code/fixtures/sample-py/calculator.py +32 -0
- package/tests/code/fixtures/sample-ts/async-operations.ts +120 -0
- package/tests/code/fixtures/sample-ts/auth.ts +31 -0
- package/tests/code/fixtures/sample-ts/config.ts +52 -0
- package/tests/code/fixtures/sample-ts/database.ts +50 -0
- package/tests/code/fixtures/sample-ts/index.ts +39 -0
- package/tests/code/fixtures/sample-ts/types-advanced.ts +132 -0
- package/tests/code/fixtures/sample-ts/utils.ts +105 -0
- package/tests/code/fixtures/sample-ts/validator.ts +169 -0
- package/tests/code/indexer.test.ts +828 -0
- package/tests/code/integration.test.ts +708 -0
- package/tests/code/metadata.test.ts +457 -0
- package/tests/code/scanner.test.ts +131 -0
- package/tests/code/sync/merkle.test.ts +406 -0
- package/tests/code/sync/snapshot.test.ts +360 -0
- package/tests/code/sync/synchronizer.test.ts +501 -0
- package/vitest.config.ts +1 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advanced TypeScript type features
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Generic constraints
|
|
6
|
+
export interface Identifiable {
|
|
7
|
+
id: string | number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class Repository<T extends Identifiable> {
|
|
11
|
+
private items: Map<string | number, T> = new Map();
|
|
12
|
+
|
|
13
|
+
add(item: T): void {
|
|
14
|
+
this.items.set(item.id, item);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get(id: string | number): T | undefined {
|
|
18
|
+
return this.items.get(id);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getAll(): T[] {
|
|
22
|
+
return Array.from(this.items.values());
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
remove(id: string | number): boolean {
|
|
26
|
+
return this.items.delete(id);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Conditional types
|
|
31
|
+
export type Awaited<T> = T extends Promise<infer U> ? U : T;
|
|
32
|
+
export type NonNullable<T> = T extends null | undefined ? never : T;
|
|
33
|
+
export type ReturnTypeOf<T> = T extends (...args: any[]) => infer R ? R : never;
|
|
34
|
+
|
|
35
|
+
// Mapped types
|
|
36
|
+
export type Readonly<T> = {
|
|
37
|
+
readonly [P in keyof T]: T[P];
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type Partial<T> = {
|
|
41
|
+
[P in keyof T]?: T[P];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type Required<T> = {
|
|
45
|
+
[P in keyof T]-?: T[P];
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Type guards
|
|
49
|
+
export function isString(value: unknown): value is string {
|
|
50
|
+
return typeof value === "string";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function isNumber(value: unknown): value is number {
|
|
54
|
+
return typeof value === "number";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function isArray<T>(value: unknown): value is T[] {
|
|
58
|
+
return Array.isArray(value);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function hasProperty<K extends string>(obj: unknown, key: K): obj is Record<K, unknown> {
|
|
62
|
+
return typeof obj === "object" && obj !== null && key in obj;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Generic factory
|
|
66
|
+
export class Factory<T> {
|
|
67
|
+
constructor(private creator: () => T) {}
|
|
68
|
+
|
|
69
|
+
create(): T {
|
|
70
|
+
return this.creator();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
createMany(count: number): T[] {
|
|
74
|
+
return Array.from({ length: count }, () => this.create());
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Builder pattern with fluent interface
|
|
79
|
+
export class QueryBuilder<T> {
|
|
80
|
+
private filters: Array<(item: T) => boolean> = [];
|
|
81
|
+
private sortFn?: (a: T, b: T) => number;
|
|
82
|
+
private limitValue?: number;
|
|
83
|
+
|
|
84
|
+
where(predicate: (item: T) => boolean): this {
|
|
85
|
+
this.filters.push(predicate);
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
orderBy(compareFn: (a: T, b: T) => number): this {
|
|
90
|
+
this.sortFn = compareFn;
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
limit(count: number): this {
|
|
95
|
+
this.limitValue = count;
|
|
96
|
+
return this;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
execute(items: T[]): T[] {
|
|
100
|
+
let result = items;
|
|
101
|
+
|
|
102
|
+
// Apply filters
|
|
103
|
+
for (const filter of this.filters) {
|
|
104
|
+
result = result.filter(filter);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Apply sorting
|
|
108
|
+
if (this.sortFn) {
|
|
109
|
+
result = result.sort(this.sortFn);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Apply limit
|
|
113
|
+
if (this.limitValue !== undefined) {
|
|
114
|
+
result = result.slice(0, this.limitValue);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Utility types
|
|
122
|
+
export type DeepPartial<T> = {
|
|
123
|
+
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export type PickByType<T, ValueType> = {
|
|
127
|
+
[K in keyof T as T[K] extends ValueType ? K : never]: T[K];
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export type OmitByType<T, ValueType> = {
|
|
131
|
+
[K in keyof T as T[K] extends ValueType ? never : K]: T[K];
|
|
132
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for string manipulation
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export function capitalize(str: string): string {
|
|
6
|
+
if (!str) return "";
|
|
7
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function slugify(text: string): string {
|
|
11
|
+
return text
|
|
12
|
+
.toLowerCase()
|
|
13
|
+
.replace(/[^\w\s-]/g, "")
|
|
14
|
+
.replace(/[\s_-]+/g, "-")
|
|
15
|
+
.replace(/^-+|-+$/g, "");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Validates email format
|
|
20
|
+
*/
|
|
21
|
+
export function isValidEmail(email: string): boolean {
|
|
22
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
23
|
+
return emailRegex.test(email);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Debounce function to limit execution rate
|
|
28
|
+
*/
|
|
29
|
+
export function debounce<T extends (...args: any[]) => any>(
|
|
30
|
+
func: T,
|
|
31
|
+
wait: number
|
|
32
|
+
): (...args: Parameters<T>) => void {
|
|
33
|
+
let timeout: NodeJS.Timeout | null = null;
|
|
34
|
+
|
|
35
|
+
return function executedFunction(...args: Parameters<T>) {
|
|
36
|
+
const later = () => {
|
|
37
|
+
timeout = null;
|
|
38
|
+
func(...args);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
if (timeout) {
|
|
42
|
+
clearTimeout(timeout);
|
|
43
|
+
}
|
|
44
|
+
timeout = setTimeout(later, wait);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Deep clone an object
|
|
50
|
+
*/
|
|
51
|
+
export function deepClone<T>(obj: T): T {
|
|
52
|
+
if (obj === null || typeof obj !== "object") {
|
|
53
|
+
return obj;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (obj instanceof Date) {
|
|
57
|
+
return new Date(obj.getTime()) as any;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (Array.isArray(obj)) {
|
|
61
|
+
const clonedArr: any[] = [];
|
|
62
|
+
for (let i = 0; i < obj.length; i++) {
|
|
63
|
+
clonedArr[i] = deepClone(obj[i]);
|
|
64
|
+
}
|
|
65
|
+
return clonedArr as any;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (obj instanceof Object) {
|
|
69
|
+
const clonedObj: any = {};
|
|
70
|
+
for (const key in obj) {
|
|
71
|
+
if (Object.hasOwn(obj, key)) {
|
|
72
|
+
clonedObj[key] = deepClone(obj[key]);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return clonedObj;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return obj;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Retry a function with exponential backoff
|
|
83
|
+
*/
|
|
84
|
+
export async function retry<T>(
|
|
85
|
+
fn: () => Promise<T>,
|
|
86
|
+
maxRetries: number = 3,
|
|
87
|
+
delay: number = 1000
|
|
88
|
+
): Promise<T> {
|
|
89
|
+
let lastError: Error;
|
|
90
|
+
|
|
91
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
92
|
+
try {
|
|
93
|
+
return await fn();
|
|
94
|
+
} catch (error) {
|
|
95
|
+
lastError = error as Error;
|
|
96
|
+
|
|
97
|
+
if (attempt < maxRetries) {
|
|
98
|
+
const backoffDelay = delay * 2 ** attempt;
|
|
99
|
+
await new Promise((resolve) => setTimeout(resolve, backoffDelay));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
throw lastError!;
|
|
105
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Complex validation logic with high cyclomatic complexity
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface ValidationResult {
|
|
6
|
+
valid: boolean;
|
|
7
|
+
errors: string[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class Validator {
|
|
11
|
+
/**
|
|
12
|
+
* Validates user input with multiple conditions
|
|
13
|
+
*/
|
|
14
|
+
validateUserInput(input: any): ValidationResult {
|
|
15
|
+
const errors: string[] = [];
|
|
16
|
+
|
|
17
|
+
if (!input) {
|
|
18
|
+
errors.push("Input is required");
|
|
19
|
+
return { valid: false, errors };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (typeof input.email === "string") {
|
|
23
|
+
if (input.email.length < 5) {
|
|
24
|
+
errors.push("Email too short");
|
|
25
|
+
} else if (input.email.length > 100) {
|
|
26
|
+
errors.push("Email too long");
|
|
27
|
+
} else if (!input.email.includes("@")) {
|
|
28
|
+
errors.push("Invalid email format");
|
|
29
|
+
} else if (input.email.startsWith("@") || input.email.endsWith("@")) {
|
|
30
|
+
errors.push("Email cannot start or end with @");
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
errors.push("Email must be a string");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (input.age !== undefined) {
|
|
37
|
+
if (typeof input.age !== "number") {
|
|
38
|
+
errors.push("Age must be a number");
|
|
39
|
+
} else if (input.age < 0) {
|
|
40
|
+
errors.push("Age cannot be negative");
|
|
41
|
+
} else if (input.age > 150) {
|
|
42
|
+
errors.push("Age seems unrealistic");
|
|
43
|
+
} else if (input.age < 13) {
|
|
44
|
+
errors.push("Must be 13 or older");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (input.password) {
|
|
49
|
+
const pwd = input.password;
|
|
50
|
+
if (pwd.length < 8) {
|
|
51
|
+
errors.push("Password too short");
|
|
52
|
+
} else if (pwd.length > 128) {
|
|
53
|
+
errors.push("Password too long");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let hasUpper = false;
|
|
57
|
+
let hasLower = false;
|
|
58
|
+
let hasDigit = false;
|
|
59
|
+
let hasSpecial = false;
|
|
60
|
+
|
|
61
|
+
for (const char of pwd) {
|
|
62
|
+
if (char >= "A" && char <= "Z") {
|
|
63
|
+
hasUpper = true;
|
|
64
|
+
} else if (char >= "a" && char <= "z") {
|
|
65
|
+
hasLower = true;
|
|
66
|
+
} else if (char >= "0" && char <= "9") {
|
|
67
|
+
hasDigit = true;
|
|
68
|
+
} else if ("!@#$%^&*()_+-=[]{}|;:,.<>?".includes(char)) {
|
|
69
|
+
hasSpecial = true;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!hasUpper) {
|
|
74
|
+
errors.push("Password needs uppercase letter");
|
|
75
|
+
}
|
|
76
|
+
if (!hasLower) {
|
|
77
|
+
errors.push("Password needs lowercase letter");
|
|
78
|
+
}
|
|
79
|
+
if (!hasDigit) {
|
|
80
|
+
errors.push("Password needs digit");
|
|
81
|
+
}
|
|
82
|
+
if (!hasSpecial) {
|
|
83
|
+
errors.push("Password needs special character");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
valid: errors.length === 0,
|
|
89
|
+
errors,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Process data with multiple switch cases and conditions
|
|
95
|
+
*/
|
|
96
|
+
processData(data: any, type: string): any {
|
|
97
|
+
switch (type) {
|
|
98
|
+
case "string":
|
|
99
|
+
return String(data);
|
|
100
|
+
case "number":
|
|
101
|
+
return Number(data);
|
|
102
|
+
case "boolean":
|
|
103
|
+
return Boolean(data);
|
|
104
|
+
case "array":
|
|
105
|
+
if (Array.isArray(data)) {
|
|
106
|
+
return data;
|
|
107
|
+
} else if (data === null || data === undefined) {
|
|
108
|
+
return [];
|
|
109
|
+
} else {
|
|
110
|
+
return [data];
|
|
111
|
+
}
|
|
112
|
+
case "object":
|
|
113
|
+
if (typeof data === "object" && data !== null) {
|
|
114
|
+
return data;
|
|
115
|
+
} else {
|
|
116
|
+
return { value: data };
|
|
117
|
+
}
|
|
118
|
+
case "json":
|
|
119
|
+
try {
|
|
120
|
+
return JSON.parse(data);
|
|
121
|
+
} catch (_e) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
default:
|
|
125
|
+
return data;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Complex nested conditions
|
|
131
|
+
*/
|
|
132
|
+
checkPermissions(user: any, resource: string, action: string): boolean {
|
|
133
|
+
if (!user) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (user.role === "admin") {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (user.role === "moderator") {
|
|
142
|
+
if (action === "read" || action === "update") {
|
|
143
|
+
return true;
|
|
144
|
+
} else if (action === "delete" && resource !== "user") {
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (user.role === "user") {
|
|
150
|
+
if (action === "read") {
|
|
151
|
+
return true;
|
|
152
|
+
} else if (action === "update" && resource === "profile") {
|
|
153
|
+
return user.id === resource;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (user.permissions && Array.isArray(user.permissions)) {
|
|
158
|
+
for (const perm of user.permissions) {
|
|
159
|
+
if (perm.resource === resource && (perm.action === action || perm.action === "*")) {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export default Validator;
|