@contiva/sapbtp-docs-mcp 1.0.1
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/LICENSE +395 -0
- package/README.md +386 -0
- package/build/cache/embedding-cache.d.ts +39 -0
- package/build/cache/embedding-cache.d.ts.map +1 -0
- package/build/cache/embedding-cache.js +105 -0
- package/build/cache/embedding-cache.js.map +1 -0
- package/build/cache/file-cache.d.ts +40 -0
- package/build/cache/file-cache.d.ts.map +1 -0
- package/build/cache/file-cache.js +124 -0
- package/build/cache/file-cache.js.map +1 -0
- package/build/cache/search-cache.d.ts +39 -0
- package/build/cache/search-cache.d.ts.map +1 -0
- package/build/cache/search-cache.js +97 -0
- package/build/cache/search-cache.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +17 -0
- package/build/index.js.map +1 -0
- package/build/indexing/file-registry.d.ts +47 -0
- package/build/indexing/file-registry.d.ts.map +1 -0
- package/build/indexing/file-registry.js +130 -0
- package/build/indexing/file-registry.js.map +1 -0
- package/build/indexing/topic-index.d.ts +57 -0
- package/build/indexing/topic-index.d.ts.map +1 -0
- package/build/indexing/topic-index.js +181 -0
- package/build/indexing/topic-index.js.map +1 -0
- package/build/parsers/links.d.ts +14 -0
- package/build/parsers/links.d.ts.map +1 -0
- package/build/parsers/links.js +80 -0
- package/build/parsers/links.js.map +1 -0
- package/build/parsers/markdown.d.ts +10 -0
- package/build/parsers/markdown.d.ts.map +1 -0
- package/build/parsers/markdown.js +120 -0
- package/build/parsers/markdown.js.map +1 -0
- package/build/parsers/metadata.d.ts +19 -0
- package/build/parsers/metadata.d.ts.map +1 -0
- package/build/parsers/metadata.js +63 -0
- package/build/parsers/metadata.js.map +1 -0
- package/build/search/fulltext.d.ts +20 -0
- package/build/search/fulltext.d.ts.map +1 -0
- package/build/search/fulltext.js +117 -0
- package/build/search/fulltext.js.map +1 -0
- package/build/search/ranking.d.ts +27 -0
- package/build/search/ranking.d.ts.map +1 -0
- package/build/search/ranking.js +119 -0
- package/build/search/ranking.js.map +1 -0
- package/build/search/semantic.d.ts +53 -0
- package/build/search/semantic.d.ts.map +1 -0
- package/build/search/semantic.js +260 -0
- package/build/search/semantic.js.map +1 -0
- package/build/search/title.d.ts +18 -0
- package/build/search/title.d.ts.map +1 -0
- package/build/search/title.js +95 -0
- package/build/search/title.js.map +1 -0
- package/build/server.d.ts +32 -0
- package/build/server.d.ts.map +1 -0
- package/build/server.js +183 -0
- package/build/server.js.map +1 -0
- package/build/tools/get-related.d.ts +64 -0
- package/build/tools/get-related.d.ts.map +1 -0
- package/build/tools/get-related.js +203 -0
- package/build/tools/get-related.js.map +1 -0
- package/build/tools/list-topics.d.ts +43 -0
- package/build/tools/list-topics.d.ts.map +1 -0
- package/build/tools/list-topics.js +63 -0
- package/build/tools/list-topics.js.map +1 -0
- package/build/tools/read-article.d.ts +42 -0
- package/build/tools/read-article.d.ts.map +1 -0
- package/build/tools/read-article.js +89 -0
- package/build/tools/read-article.js.map +1 -0
- package/build/tools/search.d.ts +57 -0
- package/build/tools/search.d.ts.map +1 -0
- package/build/tools/search.js +109 -0
- package/build/tools/search.js.map +1 -0
- package/build/types/index.d.ts +179 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/index.js +2 -0
- package/build/types/index.js.map +1 -0
- package/build/utils/docs-downloader.d.ts +9 -0
- package/build/utils/docs-downloader.d.ts.map +1 -0
- package/build/utils/docs-downloader.js +82 -0
- package/build/utils/docs-downloader.js.map +1 -0
- package/build/utils/paths.d.ts +67 -0
- package/build/utils/paths.d.ts.map +1 -0
- package/build/utils/paths.js +132 -0
- package/build/utils/paths.js.map +1 -0
- package/build/utils/text-processing.d.ts +62 -0
- package/build/utils/text-processing.d.ts.map +1 -0
- package/build/utils/text-processing.js +214 -0
- package/build/utils/text-processing.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { stat } from 'fs/promises';
|
|
2
|
+
import { parseMarkdown } from '../parsers/markdown.js';
|
|
3
|
+
/**
|
|
4
|
+
* LRU Cache for parsed documents
|
|
5
|
+
*/
|
|
6
|
+
export class FileCache {
|
|
7
|
+
cache = new Map();
|
|
8
|
+
maxSize;
|
|
9
|
+
hits = 0;
|
|
10
|
+
misses = 0;
|
|
11
|
+
constructor(maxSize = 100) {
|
|
12
|
+
this.maxSize = maxSize;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Gets a parsed document from cache or parses it
|
|
16
|
+
*/
|
|
17
|
+
async get(filePath) {
|
|
18
|
+
const cached = this.cache.get(filePath);
|
|
19
|
+
if (cached) {
|
|
20
|
+
// Check if file has been modified
|
|
21
|
+
try {
|
|
22
|
+
const stats = await stat(filePath);
|
|
23
|
+
if (cached.mtime && stats.mtime.getTime() === cached.mtime) {
|
|
24
|
+
// Cache hit - move to end (most recently used)
|
|
25
|
+
this.cache.delete(filePath);
|
|
26
|
+
this.cache.set(filePath, cached);
|
|
27
|
+
this.hits++;
|
|
28
|
+
return cached.data;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
// File might not exist anymore, remove from cache
|
|
33
|
+
this.cache.delete(filePath);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Cache miss - parse the file
|
|
37
|
+
this.misses++;
|
|
38
|
+
const document = await parseMarkdown(filePath);
|
|
39
|
+
// Add to cache
|
|
40
|
+
await this.set(filePath, document);
|
|
41
|
+
return document;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Sets a parsed document in the cache
|
|
45
|
+
*/
|
|
46
|
+
async set(filePath, document) {
|
|
47
|
+
// Get file modification time
|
|
48
|
+
let mtime;
|
|
49
|
+
try {
|
|
50
|
+
const stats = await stat(filePath);
|
|
51
|
+
mtime = stats.mtime.getTime();
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
// File might not exist, continue without mtime
|
|
55
|
+
}
|
|
56
|
+
// If cache is full, remove least recently used (first item)
|
|
57
|
+
if (this.cache.size >= this.maxSize) {
|
|
58
|
+
const firstKey = this.cache.keys().next().value;
|
|
59
|
+
if (firstKey) {
|
|
60
|
+
this.cache.delete(firstKey);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
this.cache.set(filePath, {
|
|
64
|
+
data: document,
|
|
65
|
+
timestamp: Date.now(),
|
|
66
|
+
mtime,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Checks if a file is in the cache and up-to-date
|
|
71
|
+
*/
|
|
72
|
+
async has(filePath) {
|
|
73
|
+
const cached = this.cache.get(filePath);
|
|
74
|
+
if (!cached) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
// Check if file has been modified
|
|
78
|
+
try {
|
|
79
|
+
const stats = await stat(filePath);
|
|
80
|
+
return cached.mtime !== undefined && stats.mtime.getTime() === cached.mtime;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
// File might not exist, remove from cache
|
|
84
|
+
this.cache.delete(filePath);
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Clears the entire cache
|
|
90
|
+
*/
|
|
91
|
+
clear() {
|
|
92
|
+
this.cache.clear();
|
|
93
|
+
this.hits = 0;
|
|
94
|
+
this.misses = 0;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Removes a specific file from cache
|
|
98
|
+
*/
|
|
99
|
+
invalidate(filePath) {
|
|
100
|
+
this.cache.delete(filePath);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Gets cache statistics
|
|
104
|
+
*/
|
|
105
|
+
getStats() {
|
|
106
|
+
return {
|
|
107
|
+
hits: this.hits,
|
|
108
|
+
misses: this.misses,
|
|
109
|
+
size: this.cache.size,
|
|
110
|
+
maxSize: this.maxSize,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Gets cache hit rate as a percentage
|
|
115
|
+
*/
|
|
116
|
+
getHitRate() {
|
|
117
|
+
const total = this.hits + this.misses;
|
|
118
|
+
if (total === 0) {
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
return (this.hits / total) * 100;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=file-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-cache.js","sourceRoot":"","sources":["../../src/cache/file-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { SearchResult } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* TTL-based cache for search results
|
|
4
|
+
*/
|
|
5
|
+
export declare class SearchCache {
|
|
6
|
+
private cache;
|
|
7
|
+
private ttl;
|
|
8
|
+
private maxSize;
|
|
9
|
+
constructor(ttlSeconds?: number);
|
|
10
|
+
/**
|
|
11
|
+
* Generates a cache key from search parameters
|
|
12
|
+
*/
|
|
13
|
+
private generateKey;
|
|
14
|
+
/**
|
|
15
|
+
* Gets search results from cache
|
|
16
|
+
*/
|
|
17
|
+
get(query: string, searchType: string, area: string): SearchResult[] | null;
|
|
18
|
+
/**
|
|
19
|
+
* Sets search results in cache
|
|
20
|
+
*/
|
|
21
|
+
set(query: string, searchType: string, area: string, results: SearchResult[]): void;
|
|
22
|
+
/**
|
|
23
|
+
* Removes expired entries from cache
|
|
24
|
+
*/
|
|
25
|
+
private cleanup;
|
|
26
|
+
/**
|
|
27
|
+
* Clears all cache entries
|
|
28
|
+
*/
|
|
29
|
+
clear(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Gets the number of entries in cache
|
|
32
|
+
*/
|
|
33
|
+
size(): number;
|
|
34
|
+
/**
|
|
35
|
+
* Checks if a search query is cached and valid
|
|
36
|
+
*/
|
|
37
|
+
has(query: string, searchType: string, area: string): boolean;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=search-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-cache.d.ts","sourceRoot":"","sources":["../../src/cache/search-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,mBAAmB,CAAC;AAGlE;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAsD;IACnE,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,OAAO,CAAc;gBAEjB,UAAU,GAAE,MAAY;IAIpC;;OAEG;IACH,OAAO,CAAC,WAAW;IAKnB;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,GAAG,IAAI;IAkB3E;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,IAAI;IAcnF;;OAEG;IACH,OAAO,CAAC,OAAO;IAuBf;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,IAAI,IAAI,MAAM;IAId;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO;CAW9D"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { hashString } from '../utils/text-processing.js';
|
|
2
|
+
/**
|
|
3
|
+
* TTL-based cache for search results
|
|
4
|
+
*/
|
|
5
|
+
export class SearchCache {
|
|
6
|
+
cache = new Map();
|
|
7
|
+
ttl; // Time to live in milliseconds
|
|
8
|
+
maxSize = 50;
|
|
9
|
+
constructor(ttlSeconds = 300) {
|
|
10
|
+
this.ttl = ttlSeconds * 1000;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Generates a cache key from search parameters
|
|
14
|
+
*/
|
|
15
|
+
generateKey(query, searchType, area) {
|
|
16
|
+
const keyString = `${query}|${searchType}|${area}`;
|
|
17
|
+
return hashString(keyString);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Gets search results from cache
|
|
21
|
+
*/
|
|
22
|
+
get(query, searchType, area) {
|
|
23
|
+
const key = this.generateKey(query, searchType, area);
|
|
24
|
+
const cached = this.cache.get(key);
|
|
25
|
+
if (!cached) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
// Check if cache entry has expired
|
|
29
|
+
const now = Date.now();
|
|
30
|
+
if (now - cached.timestamp > this.ttl) {
|
|
31
|
+
this.cache.delete(key);
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return cached.data;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Sets search results in cache
|
|
38
|
+
*/
|
|
39
|
+
set(query, searchType, area, results) {
|
|
40
|
+
const key = this.generateKey(query, searchType, area);
|
|
41
|
+
// If cache is full, remove oldest entries
|
|
42
|
+
if (this.cache.size >= this.maxSize) {
|
|
43
|
+
this.cleanup();
|
|
44
|
+
}
|
|
45
|
+
this.cache.set(key, {
|
|
46
|
+
data: results,
|
|
47
|
+
timestamp: Date.now(),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Removes expired entries from cache
|
|
52
|
+
*/
|
|
53
|
+
cleanup() {
|
|
54
|
+
const now = Date.now();
|
|
55
|
+
const toDelete = [];
|
|
56
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
57
|
+
if (now - entry.timestamp > this.ttl) {
|
|
58
|
+
toDelete.push(key);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
for (const key of toDelete) {
|
|
62
|
+
this.cache.delete(key);
|
|
63
|
+
}
|
|
64
|
+
// If still full after cleanup, remove oldest entry
|
|
65
|
+
if (this.cache.size >= this.maxSize) {
|
|
66
|
+
const firstKey = this.cache.keys().next().value;
|
|
67
|
+
if (firstKey) {
|
|
68
|
+
this.cache.delete(firstKey);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Clears all cache entries
|
|
74
|
+
*/
|
|
75
|
+
clear() {
|
|
76
|
+
this.cache.clear();
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Gets the number of entries in cache
|
|
80
|
+
*/
|
|
81
|
+
size() {
|
|
82
|
+
return this.cache.size;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Checks if a search query is cached and valid
|
|
86
|
+
*/
|
|
87
|
+
has(query, searchType, area) {
|
|
88
|
+
const key = this.generateKey(query, searchType, area);
|
|
89
|
+
const cached = this.cache.get(key);
|
|
90
|
+
if (!cached) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
const now = Date.now();
|
|
94
|
+
return now - cached.timestamp <= this.ttl;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=search-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-cache.js","sourceRoot":"","sources":["../../src/cache/search-cache.ts"],"names":[],"mappings":"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"}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/build/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { SAPISDocsServer } from './server.js';
|
|
3
|
+
/**
|
|
4
|
+
* Main entry point for the SAP Business Technology Platform Documentation MCP Server
|
|
5
|
+
*/
|
|
6
|
+
async function main() {
|
|
7
|
+
try {
|
|
8
|
+
const server = new SAPISDocsServer();
|
|
9
|
+
await server.start();
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
console.error('Failed to start server:', error);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
main();
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;QACrC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { FileRegistryEntry, DocumentArea } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* File Registry - maintains a fast lookup of all documentation files
|
|
4
|
+
*/
|
|
5
|
+
export declare class FileRegistry {
|
|
6
|
+
private registry;
|
|
7
|
+
private loioIndex;
|
|
8
|
+
private docsPath;
|
|
9
|
+
constructor(docsPath?: string);
|
|
10
|
+
/**
|
|
11
|
+
* Builds the file registry by scanning all documentation files
|
|
12
|
+
*/
|
|
13
|
+
build(): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Recursively scans a directory for markdown files
|
|
16
|
+
*/
|
|
17
|
+
private scanDirectory;
|
|
18
|
+
/**
|
|
19
|
+
* Adds a file to the registry
|
|
20
|
+
*/
|
|
21
|
+
private addFile;
|
|
22
|
+
/**
|
|
23
|
+
* Gets a file entry by path
|
|
24
|
+
*/
|
|
25
|
+
getByPath(filePath: string): FileRegistryEntry | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Gets a file path by LOIO ID
|
|
28
|
+
*/
|
|
29
|
+
getByLoioId(loioId: string): FileRegistryEntry | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Gets all files in a specific area
|
|
32
|
+
*/
|
|
33
|
+
getByArea(area: DocumentArea): FileRegistryEntry[];
|
|
34
|
+
/**
|
|
35
|
+
* Gets all files
|
|
36
|
+
*/
|
|
37
|
+
getAllFiles(): FileRegistryEntry[];
|
|
38
|
+
/**
|
|
39
|
+
* Searches files by title (case-insensitive partial match)
|
|
40
|
+
*/
|
|
41
|
+
searchByTitle(query: string): FileRegistryEntry[];
|
|
42
|
+
/**
|
|
43
|
+
* Gets the total number of files in the registry
|
|
44
|
+
*/
|
|
45
|
+
size(): number;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=file-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-registry.d.ts","sourceRoot":"","sources":["../../src/indexing/file-registry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAIzE;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAA6C;IAC7D,OAAO,CAAC,SAAS,CAAkC;IACnD,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,CAAC,EAAE,MAAM;IAI7B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAe5B;;OAEG;YACW,aAAa;IAmB3B;;OAEG;YACW,OAAO;IA4CrB;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAI1D;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAK1D;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,iBAAiB,EAAE;IAIlD;;OAEG;IACH,WAAW,IAAI,iBAAiB,EAAE;IAIlC;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAOjD;;OAEG;IACH,IAAI,IAAI,MAAM;CAGf"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { readdir, readFile } from 'fs/promises';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { resolveDocsPath, getRelativePath } from '../utils/paths.js';
|
|
4
|
+
import { extractLoioId } from '../parsers/metadata.js';
|
|
5
|
+
/**
|
|
6
|
+
* File Registry - maintains a fast lookup of all documentation files
|
|
7
|
+
*/
|
|
8
|
+
export class FileRegistry {
|
|
9
|
+
registry = new Map();
|
|
10
|
+
loioIndex = new Map(); // loioId -> filePath
|
|
11
|
+
docsPath;
|
|
12
|
+
constructor(docsPath) {
|
|
13
|
+
this.docsPath = docsPath || resolveDocsPath();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Builds the file registry by scanning all documentation files
|
|
17
|
+
*/
|
|
18
|
+
async build() {
|
|
19
|
+
console.error('Building file registry...');
|
|
20
|
+
const startTime = Date.now();
|
|
21
|
+
const areas = ['ISuite', 'ci', 'apim'];
|
|
22
|
+
for (const area of areas) {
|
|
23
|
+
const areaPath = join(this.docsPath, area);
|
|
24
|
+
await this.scanDirectory(areaPath, area);
|
|
25
|
+
}
|
|
26
|
+
const elapsed = Date.now() - startTime;
|
|
27
|
+
console.error(`File registry built: ${this.registry.size} files in ${elapsed}ms`);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Recursively scans a directory for markdown files
|
|
31
|
+
*/
|
|
32
|
+
async scanDirectory(dir, area) {
|
|
33
|
+
try {
|
|
34
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
35
|
+
for (const entry of entries) {
|
|
36
|
+
const fullPath = join(dir, entry.name);
|
|
37
|
+
if (entry.isDirectory()) {
|
|
38
|
+
await this.scanDirectory(fullPath, area);
|
|
39
|
+
}
|
|
40
|
+
else if (entry.isFile() && entry.name.endsWith('.md') && entry.name !== 'index.md') {
|
|
41
|
+
await this.addFile(fullPath, area);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
// Directory might not exist, skip
|
|
47
|
+
console.error(`Warning: Could not scan directory ${dir}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Adds a file to the registry
|
|
52
|
+
*/
|
|
53
|
+
async addFile(filePath, area) {
|
|
54
|
+
try {
|
|
55
|
+
// Read just the first 1000 chars to find LOIO and title
|
|
56
|
+
const content = await readFile(filePath, 'utf-8');
|
|
57
|
+
const preview = content.substring(0, 1000);
|
|
58
|
+
const loioId = extractLoioId(preview);
|
|
59
|
+
// Extract title from first H1
|
|
60
|
+
const titleMatch = preview.match(/^#\s+(.+)$/m);
|
|
61
|
+
let title = '';
|
|
62
|
+
if (titleMatch) {
|
|
63
|
+
title = titleMatch[1].trim();
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// Fallback: use filename
|
|
67
|
+
const filename = filePath.split('/').pop() || filePath;
|
|
68
|
+
const withoutExt = filename.replace(/\.md$/, '');
|
|
69
|
+
const withoutHash = withoutExt.replace(/-[a-f0-9]{7}$/, '');
|
|
70
|
+
title = withoutHash
|
|
71
|
+
.split('-')
|
|
72
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
73
|
+
.join(' ');
|
|
74
|
+
}
|
|
75
|
+
const entry = {
|
|
76
|
+
filePath,
|
|
77
|
+
relativePath: getRelativePath(filePath, this.docsPath),
|
|
78
|
+
title,
|
|
79
|
+
loioId,
|
|
80
|
+
area,
|
|
81
|
+
};
|
|
82
|
+
this.registry.set(filePath, entry);
|
|
83
|
+
if (loioId) {
|
|
84
|
+
this.loioIndex.set(loioId, filePath);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
console.error(`Warning: Could not add file ${filePath} to registry`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Gets a file entry by path
|
|
93
|
+
*/
|
|
94
|
+
getByPath(filePath) {
|
|
95
|
+
return this.registry.get(filePath);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Gets a file path by LOIO ID
|
|
99
|
+
*/
|
|
100
|
+
getByLoioId(loioId) {
|
|
101
|
+
const filePath = this.loioIndex.get(loioId);
|
|
102
|
+
return filePath ? this.registry.get(filePath) : undefined;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Gets all files in a specific area
|
|
106
|
+
*/
|
|
107
|
+
getByArea(area) {
|
|
108
|
+
return Array.from(this.registry.values()).filter(entry => entry.area === area);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Gets all files
|
|
112
|
+
*/
|
|
113
|
+
getAllFiles() {
|
|
114
|
+
return Array.from(this.registry.values());
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Searches files by title (case-insensitive partial match)
|
|
118
|
+
*/
|
|
119
|
+
searchByTitle(query) {
|
|
120
|
+
const normalizedQuery = query.toLowerCase();
|
|
121
|
+
return Array.from(this.registry.values()).filter(entry => entry.title.toLowerCase().includes(normalizedQuery));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Gets the total number of files in the registry
|
|
125
|
+
*/
|
|
126
|
+
size() {
|
|
127
|
+
return this.registry.size;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=file-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-registry.js","sourceRoot":"","sources":["../../src/indexing/file-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Topic, TopicHierarchy, DocumentArea } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Topic Index - parses index.md files to build hierarchical topic structure
|
|
4
|
+
*/
|
|
5
|
+
export declare class TopicIndex {
|
|
6
|
+
private hierarchies;
|
|
7
|
+
private docsPath;
|
|
8
|
+
constructor(docsPath?: string);
|
|
9
|
+
/**
|
|
10
|
+
* Builds the topic index by parsing index.md files
|
|
11
|
+
*/
|
|
12
|
+
build(): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Parses an index.md file to extract topic hierarchy
|
|
15
|
+
*/
|
|
16
|
+
private parseIndexFile;
|
|
17
|
+
/**
|
|
18
|
+
* Parses topics from index.md content
|
|
19
|
+
* Expects format like:
|
|
20
|
+
* - [Topic Title](path/to/file.md)
|
|
21
|
+
* - [Subtopic](path/to/subtopic.md)
|
|
22
|
+
*/
|
|
23
|
+
private parseTopicsFromContent;
|
|
24
|
+
/**
|
|
25
|
+
* Counts total number of topics (including children)
|
|
26
|
+
*/
|
|
27
|
+
private countTopics;
|
|
28
|
+
/**
|
|
29
|
+
* Gets the topic hierarchy for a specific area
|
|
30
|
+
*/
|
|
31
|
+
getHierarchy(area: DocumentArea): TopicHierarchy | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Gets topics up to a specific depth
|
|
34
|
+
*/
|
|
35
|
+
getTopicsWithDepth(area: DocumentArea, maxDepth: number): Topic[];
|
|
36
|
+
/**
|
|
37
|
+
* Filters topics by maximum depth
|
|
38
|
+
*/
|
|
39
|
+
private filterByDepth;
|
|
40
|
+
/**
|
|
41
|
+
* Finds topics under a specific parent path
|
|
42
|
+
*/
|
|
43
|
+
getTopicsUnderPath(area: DocumentArea, parentPath: string): Topic[];
|
|
44
|
+
/**
|
|
45
|
+
* Finds a topic by its path
|
|
46
|
+
*/
|
|
47
|
+
private findTopicByPath;
|
|
48
|
+
/**
|
|
49
|
+
* Flattens the topic hierarchy into a list
|
|
50
|
+
*/
|
|
51
|
+
flattenTopics(topics: Topic[]): Topic[];
|
|
52
|
+
/**
|
|
53
|
+
* Gets all topics for an area (flattened)
|
|
54
|
+
*/
|
|
55
|
+
getAllTopics(area: DocumentArea): Topic[];
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=topic-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"topic-index.d.ts","sourceRoot":"","sources":["../../src/indexing/topic-index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAG7E;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,WAAW,CAAgD;IACnE,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,CAAC,EAAE,MAAM;IAI7B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB5B;;OAEG;YACW,cAAc;IAa5B;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;IAwD9B;;OAEG;IACH,OAAO,CAAC,WAAW;IAUnB;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,cAAc,GAAG,SAAS;IAI5D;;OAEG;IACH,kBAAkB,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,EAAE;IAUjE;;OAEG;IACH,OAAO,CAAC,aAAa;IAWrB;;OAEG;IACH,kBAAkB,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,KAAK,EAAE;IAYnE;;OAEG;IACH,OAAO,CAAC,eAAe;IAevB;;OAEG;IACH,aAAa,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE;IAWvC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,KAAK,EAAE;CAS1C"}
|