@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,181 @@
|
|
|
1
|
+
import { readFile } from 'fs/promises';
|
|
2
|
+
import { dirname, resolve } from 'path';
|
|
3
|
+
import { resolveDocsPath, getIndexPath } from '../utils/paths.js';
|
|
4
|
+
/**
|
|
5
|
+
* Topic Index - parses index.md files to build hierarchical topic structure
|
|
6
|
+
*/
|
|
7
|
+
export class TopicIndex {
|
|
8
|
+
hierarchies = new Map();
|
|
9
|
+
docsPath;
|
|
10
|
+
constructor(docsPath) {
|
|
11
|
+
this.docsPath = docsPath || resolveDocsPath();
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Builds the topic index by parsing index.md files
|
|
15
|
+
*/
|
|
16
|
+
async build() {
|
|
17
|
+
console.error('Building topic index...');
|
|
18
|
+
const startTime = Date.now();
|
|
19
|
+
const areas = ['ISuite', 'apim'];
|
|
20
|
+
for (const area of areas) {
|
|
21
|
+
try {
|
|
22
|
+
const hierarchy = await this.parseIndexFile(area);
|
|
23
|
+
this.hierarchies.set(area, hierarchy);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.error(`Warning: Could not parse index for ${area}:`, error);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const elapsed = Date.now() - startTime;
|
|
30
|
+
console.error(`Topic index built in ${elapsed}ms`);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Parses an index.md file to extract topic hierarchy
|
|
34
|
+
*/
|
|
35
|
+
async parseIndexFile(area) {
|
|
36
|
+
const indexPath = getIndexPath(area, this.docsPath);
|
|
37
|
+
const content = await readFile(indexPath, 'utf-8');
|
|
38
|
+
const topics = this.parseTopicsFromContent(content, indexPath);
|
|
39
|
+
return {
|
|
40
|
+
area,
|
|
41
|
+
topics,
|
|
42
|
+
totalTopics: this.countTopics(topics),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Parses topics from index.md content
|
|
47
|
+
* Expects format like:
|
|
48
|
+
* - [Topic Title](path/to/file.md)
|
|
49
|
+
* - [Subtopic](path/to/subtopic.md)
|
|
50
|
+
*/
|
|
51
|
+
parseTopicsFromContent(content, indexPath) {
|
|
52
|
+
const lines = content.split('\n');
|
|
53
|
+
const topics = [];
|
|
54
|
+
const stack = [];
|
|
55
|
+
const indexDir = dirname(indexPath);
|
|
56
|
+
for (const line of lines) {
|
|
57
|
+
// Match list items: - [Title](path.md) or - [Title](path.md)
|
|
58
|
+
const match = line.match(/^(\s*)-\s*\[([^\]]+)\]\(([^)]+)\)/);
|
|
59
|
+
if (!match) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const indent = match[1].length;
|
|
63
|
+
const title = match[2].trim();
|
|
64
|
+
const href = match[3];
|
|
65
|
+
// Skip external links
|
|
66
|
+
if (href.startsWith('http://') || href.startsWith('https://')) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
// Resolve relative path
|
|
70
|
+
const [pathPart] = href.split('#');
|
|
71
|
+
const absolutePath = resolve(indexDir, pathPart);
|
|
72
|
+
const level = Math.floor(indent / 2); // Assuming 2 spaces per level
|
|
73
|
+
const topic = {
|
|
74
|
+
title,
|
|
75
|
+
path: absolutePath,
|
|
76
|
+
level,
|
|
77
|
+
children: [],
|
|
78
|
+
};
|
|
79
|
+
// Pop stack until we find the correct parent level
|
|
80
|
+
while (stack.length > 0 && stack[stack.length - 1].indent >= indent) {
|
|
81
|
+
stack.pop();
|
|
82
|
+
}
|
|
83
|
+
if (stack.length === 0) {
|
|
84
|
+
// Top-level topic
|
|
85
|
+
topics.push(topic);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// Add as child to parent
|
|
89
|
+
stack[stack.length - 1].topic.children.push(topic);
|
|
90
|
+
}
|
|
91
|
+
stack.push({ topic, indent });
|
|
92
|
+
}
|
|
93
|
+
return topics;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Counts total number of topics (including children)
|
|
97
|
+
*/
|
|
98
|
+
countTopics(topics) {
|
|
99
|
+
let count = topics.length;
|
|
100
|
+
for (const topic of topics) {
|
|
101
|
+
count += this.countTopics(topic.children);
|
|
102
|
+
}
|
|
103
|
+
return count;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Gets the topic hierarchy for a specific area
|
|
107
|
+
*/
|
|
108
|
+
getHierarchy(area) {
|
|
109
|
+
return this.hierarchies.get(area);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Gets topics up to a specific depth
|
|
113
|
+
*/
|
|
114
|
+
getTopicsWithDepth(area, maxDepth) {
|
|
115
|
+
const hierarchy = this.hierarchies.get(area);
|
|
116
|
+
if (!hierarchy) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
return this.filterByDepth(hierarchy.topics, maxDepth, 0);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Filters topics by maximum depth
|
|
123
|
+
*/
|
|
124
|
+
filterByDepth(topics, maxDepth, currentDepth) {
|
|
125
|
+
if (currentDepth >= maxDepth) {
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
return topics.map(topic => ({
|
|
129
|
+
...topic,
|
|
130
|
+
children: this.filterByDepth(topic.children, maxDepth, currentDepth + 1),
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Finds topics under a specific parent path
|
|
135
|
+
*/
|
|
136
|
+
getTopicsUnderPath(area, parentPath) {
|
|
137
|
+
const hierarchy = this.hierarchies.get(area);
|
|
138
|
+
if (!hierarchy) {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
const topic = this.findTopicByPath(hierarchy.topics, parentPath);
|
|
142
|
+
return topic ? topic.children : [];
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Finds a topic by its path
|
|
146
|
+
*/
|
|
147
|
+
findTopicByPath(topics, targetPath) {
|
|
148
|
+
for (const topic of topics) {
|
|
149
|
+
if (topic.path === targetPath) {
|
|
150
|
+
return topic;
|
|
151
|
+
}
|
|
152
|
+
const found = this.findTopicByPath(topic.children, targetPath);
|
|
153
|
+
if (found) {
|
|
154
|
+
return found;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Flattens the topic hierarchy into a list
|
|
161
|
+
*/
|
|
162
|
+
flattenTopics(topics) {
|
|
163
|
+
const flat = [];
|
|
164
|
+
for (const topic of topics) {
|
|
165
|
+
flat.push(topic);
|
|
166
|
+
flat.push(...this.flattenTopics(topic.children));
|
|
167
|
+
}
|
|
168
|
+
return flat;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Gets all topics for an area (flattened)
|
|
172
|
+
*/
|
|
173
|
+
getAllTopics(area) {
|
|
174
|
+
const hierarchy = this.hierarchies.get(area);
|
|
175
|
+
if (!hierarchy) {
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
return this.flattenTopics(hierarchy.topics);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=topic-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"topic-index.js","sourceRoot":"","sources":["../../src/indexing/topic-index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ParsedLink } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Extracts all links from markdown content
|
|
4
|
+
*/
|
|
5
|
+
export declare function extractLinks(content: string, sourcePath: string): ParsedLink[];
|
|
6
|
+
/**
|
|
7
|
+
* Resolves all relative links in markdown content to absolute paths
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveLinksInContent(content: string, sourcePath: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Extracts links from a "Related Information" section
|
|
12
|
+
*/
|
|
13
|
+
export declare function extractRelatedLinks(content: string, sourcePath: string): ParsedLink[];
|
|
14
|
+
//# sourceMappingURL=links.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../src/parsers/links.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,EAAE,CAiD9E;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAkBjF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,EAAE,CAWrF"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { resolveRelativeLink, isExternalLink } from '../utils/paths.js';
|
|
2
|
+
/**
|
|
3
|
+
* Extracts all links from markdown content
|
|
4
|
+
*/
|
|
5
|
+
export function extractLinks(content, sourcePath) {
|
|
6
|
+
const links = [];
|
|
7
|
+
const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
|
|
8
|
+
let match;
|
|
9
|
+
while ((match = linkRegex.exec(content)) !== null) {
|
|
10
|
+
const text = match[1];
|
|
11
|
+
const href = match[2];
|
|
12
|
+
// Skip if it's just an anchor or external link handled separately
|
|
13
|
+
if (href.startsWith('#')) {
|
|
14
|
+
links.push({
|
|
15
|
+
text,
|
|
16
|
+
href,
|
|
17
|
+
absolutePath: sourcePath,
|
|
18
|
+
isExternal: false,
|
|
19
|
+
anchor: href.substring(1),
|
|
20
|
+
});
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const external = isExternalLink(href);
|
|
24
|
+
if (external) {
|
|
25
|
+
links.push({
|
|
26
|
+
text,
|
|
27
|
+
href,
|
|
28
|
+
absolutePath: href,
|
|
29
|
+
isExternal: true,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
// Split href into path and anchor
|
|
34
|
+
const [pathPart, anchor] = href.split('#');
|
|
35
|
+
const absolutePath = pathPart
|
|
36
|
+
? resolveRelativeLink(sourcePath, pathPart)
|
|
37
|
+
: sourcePath;
|
|
38
|
+
links.push({
|
|
39
|
+
text,
|
|
40
|
+
href,
|
|
41
|
+
absolutePath,
|
|
42
|
+
isExternal: false,
|
|
43
|
+
anchor,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return links;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Resolves all relative links in markdown content to absolute paths
|
|
51
|
+
*/
|
|
52
|
+
export function resolveLinksInContent(content, sourcePath) {
|
|
53
|
+
return content.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, text, href) => {
|
|
54
|
+
// Skip external links and anchors
|
|
55
|
+
if (isExternalLink(href) || href.startsWith('#')) {
|
|
56
|
+
return match;
|
|
57
|
+
}
|
|
58
|
+
const [pathPart, anchor] = href.split('#');
|
|
59
|
+
if (!pathPart) {
|
|
60
|
+
return match;
|
|
61
|
+
}
|
|
62
|
+
const absolutePath = resolveRelativeLink(sourcePath, pathPart);
|
|
63
|
+
const newHref = anchor ? `${absolutePath}#${anchor}` : absolutePath;
|
|
64
|
+
return `[${text}](${newHref})`;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Extracts links from a "Related Information" section
|
|
69
|
+
*/
|
|
70
|
+
export function extractRelatedLinks(content, sourcePath) {
|
|
71
|
+
// Look for "Related Information" section
|
|
72
|
+
const relatedSectionRegex = /\*\*Related Information\*\*\s*([\s\S]*?)(?=\n##|$)/i;
|
|
73
|
+
const match = content.match(relatedSectionRegex);
|
|
74
|
+
if (!match) {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
const sectionContent = match[1];
|
|
78
|
+
return extractLinks(sectionContent, sourcePath);
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=links.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"links.js","sourceRoot":"","sources":["../../src/parsers/links.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ParsedDocument } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parses a markdown file and extracts all relevant information
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseMarkdown(filePath: string): Promise<ParsedDocument>;
|
|
6
|
+
/**
|
|
7
|
+
* Parses markdown to get structured AST (for advanced processing)
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseMarkdownToAST(content: string): Promise<import("mdast").Root>;
|
|
10
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/parsers/markdown.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAW,MAAM,mBAAmB,CAAC;AAIjE;;GAEG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAgC7E;AA4FD;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,iCAIvD"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { readFile } from 'fs/promises';
|
|
2
|
+
import { remark } from 'remark';
|
|
3
|
+
import remarkGfm from 'remark-gfm';
|
|
4
|
+
import stripMarkdown from 'strip-markdown';
|
|
5
|
+
import { extractLoioId, extractMetadata } from './metadata.js';
|
|
6
|
+
import { extractLinks } from './links.js';
|
|
7
|
+
/**
|
|
8
|
+
* Parses a markdown file and extracts all relevant information
|
|
9
|
+
*/
|
|
10
|
+
export async function parseMarkdown(filePath) {
|
|
11
|
+
const content = await readFile(filePath, 'utf-8');
|
|
12
|
+
// Extract metadata
|
|
13
|
+
const loioId = extractLoioId(content);
|
|
14
|
+
const metadata = await extractMetadata(filePath, content);
|
|
15
|
+
// Extract title (first H1 heading or from filename)
|
|
16
|
+
const title = extractTitle(content, filePath);
|
|
17
|
+
// Extract headings
|
|
18
|
+
const headings = extractHeadings(content);
|
|
19
|
+
// Extract links
|
|
20
|
+
const links = extractLinks(content, filePath);
|
|
21
|
+
// Extract images
|
|
22
|
+
const images = extractImages(content);
|
|
23
|
+
// Get clean text (markdown stripped)
|
|
24
|
+
const cleanText = await stripMarkdownContent(content);
|
|
25
|
+
return {
|
|
26
|
+
title,
|
|
27
|
+
loioId,
|
|
28
|
+
content,
|
|
29
|
+
cleanText,
|
|
30
|
+
links,
|
|
31
|
+
headings,
|
|
32
|
+
images,
|
|
33
|
+
metadata,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Extracts the title from the markdown content (first H1 heading)
|
|
38
|
+
*/
|
|
39
|
+
function extractTitle(content, filePath) {
|
|
40
|
+
// Try to find first H1 heading
|
|
41
|
+
const h1Match = content.match(/^#\s+(.+)$/m);
|
|
42
|
+
if (h1Match) {
|
|
43
|
+
return h1Match[1].trim();
|
|
44
|
+
}
|
|
45
|
+
// Fallback: use filename without extension and hash
|
|
46
|
+
const filename = filePath.split('/').pop() || filePath;
|
|
47
|
+
const withoutExt = filename.replace(/\.md$/, '');
|
|
48
|
+
const withoutHash = withoutExt.replace(/-[a-f0-9]{7}$/, '');
|
|
49
|
+
// Convert kebab-case to Title Case
|
|
50
|
+
return withoutHash
|
|
51
|
+
.split('-')
|
|
52
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
53
|
+
.join(' ');
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Extracts all headings from markdown content
|
|
57
|
+
*/
|
|
58
|
+
function extractHeadings(content) {
|
|
59
|
+
const headings = [];
|
|
60
|
+
const headingRegex = /^(#{1,6})\s+(.+)$/gm;
|
|
61
|
+
let match;
|
|
62
|
+
while ((match = headingRegex.exec(content)) !== null) {
|
|
63
|
+
const level = match[1].length;
|
|
64
|
+
const text = match[2].trim();
|
|
65
|
+
const anchor = createAnchor(text);
|
|
66
|
+
headings.push({
|
|
67
|
+
level,
|
|
68
|
+
text,
|
|
69
|
+
anchor,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return headings;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Creates an anchor ID from heading text (GitHub-style)
|
|
76
|
+
*/
|
|
77
|
+
function createAnchor(text) {
|
|
78
|
+
return text
|
|
79
|
+
.toLowerCase()
|
|
80
|
+
.replace(/[^\w\s-]/g, '')
|
|
81
|
+
.replace(/\s+/g, '-')
|
|
82
|
+
.replace(/-+/g, '-')
|
|
83
|
+
.replace(/^-|-$/g, '');
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Extracts image references from markdown content
|
|
87
|
+
*/
|
|
88
|
+
function extractImages(content) {
|
|
89
|
+
const images = [];
|
|
90
|
+
const imageRegex = /!\[.*?\]\(([^)]+)\)/g;
|
|
91
|
+
let match;
|
|
92
|
+
while ((match = imageRegex.exec(content)) !== null) {
|
|
93
|
+
images.push(match[1]);
|
|
94
|
+
}
|
|
95
|
+
return images;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Strips markdown formatting from content to get clean text
|
|
99
|
+
*/
|
|
100
|
+
async function stripMarkdownContent(content) {
|
|
101
|
+
const result = await remark()
|
|
102
|
+
.use(remarkGfm)
|
|
103
|
+
.use(stripMarkdown)
|
|
104
|
+
.process(content);
|
|
105
|
+
return String(result)
|
|
106
|
+
// Remove LOIO comments
|
|
107
|
+
.replace(/<!--\s*loio[a-f0-9]+\s*-->/g, '')
|
|
108
|
+
// Normalize whitespace
|
|
109
|
+
.replace(/\n\n+/g, '\n\n')
|
|
110
|
+
.trim();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Parses markdown to get structured AST (for advanced processing)
|
|
114
|
+
*/
|
|
115
|
+
export async function parseMarkdownToAST(content) {
|
|
116
|
+
const processor = remark().use(remarkGfm);
|
|
117
|
+
const tree = processor.parse(content);
|
|
118
|
+
return tree;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/parsers/markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DocumentMetadata } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Extracts the LOIO ID from markdown content
|
|
4
|
+
* Format: <!-- loio5cc6987511104c418b7cb4c25f3d9cb0 -->
|
|
5
|
+
*/
|
|
6
|
+
export declare function extractLoioId(content: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Extracts complete document metadata
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractMetadata(filePath: string, content: string): Promise<DocumentMetadata>;
|
|
11
|
+
/**
|
|
12
|
+
* Checks if a file path looks like a documentation file
|
|
13
|
+
*/
|
|
14
|
+
export declare function isDocumentationFile(filePath: string): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Checks if a file is an index file
|
|
17
|
+
*/
|
|
18
|
+
export declare function isIndexFile(filePath: string): boolean;
|
|
19
|
+
//# sourceMappingURL=metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/parsers/metadata.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAG1D;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASrD;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAoClG;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAErD"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { stat } from 'fs/promises';
|
|
2
|
+
import { getDocumentArea, getRelativePath, resolveDocsPath } from '../utils/paths.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extracts the LOIO ID from markdown content
|
|
5
|
+
* Format: <!-- loio5cc6987511104c418b7cb4c25f3d9cb0 -->
|
|
6
|
+
*/
|
|
7
|
+
export function extractLoioId(content) {
|
|
8
|
+
const match = content.match(/<!--\s*loio([a-f0-9]+)\s*-->/);
|
|
9
|
+
if (match) {
|
|
10
|
+
return `loio${match[1]}`;
|
|
11
|
+
}
|
|
12
|
+
// Return empty string if no LOIO ID found
|
|
13
|
+
return '';
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Extracts complete document metadata
|
|
17
|
+
*/
|
|
18
|
+
export async function extractMetadata(filePath, content) {
|
|
19
|
+
const loioId = extractLoioId(content);
|
|
20
|
+
const area = getDocumentArea(filePath);
|
|
21
|
+
const docsPath = resolveDocsPath();
|
|
22
|
+
const relativePath = getRelativePath(filePath, docsPath);
|
|
23
|
+
// Get file stats
|
|
24
|
+
const stats = await stat(filePath);
|
|
25
|
+
// Extract title from first H1 heading
|
|
26
|
+
const titleMatch = content.match(/^#\s+(.+)$/m);
|
|
27
|
+
let title = '';
|
|
28
|
+
if (titleMatch) {
|
|
29
|
+
title = titleMatch[1].trim();
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// Fallback: use filename
|
|
33
|
+
const filename = filePath.split('/').pop() || filePath;
|
|
34
|
+
const withoutExt = filename.replace(/\.md$/, '');
|
|
35
|
+
const withoutHash = withoutExt.replace(/-[a-f0-9]{7}$/, '');
|
|
36
|
+
title = withoutHash
|
|
37
|
+
.split('-')
|
|
38
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
39
|
+
.join(' ');
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
loioId,
|
|
43
|
+
title,
|
|
44
|
+
area,
|
|
45
|
+
filePath,
|
|
46
|
+
relativePath,
|
|
47
|
+
lastModified: stats.mtime,
|
|
48
|
+
size: stats.size,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Checks if a file path looks like a documentation file
|
|
53
|
+
*/
|
|
54
|
+
export function isDocumentationFile(filePath) {
|
|
55
|
+
return filePath.endsWith('.md') && !filePath.endsWith('index.md');
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Checks if a file is an index file
|
|
59
|
+
*/
|
|
60
|
+
export function isIndexFile(filePath) {
|
|
61
|
+
return filePath.endsWith('index.md');
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/parsers/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEtF;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAE5D,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3B,CAAC;IAED,0CAA0C;IAC1C,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAgB,EAAE,OAAe;IACrE,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,MAAM,YAAY,GAAG,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEzD,iBAAiB;IACjB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;IAEnC,sCAAsC;IACtC,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAChD,IAAI,KAAK,GAAG,EAAE,CAAC;IAEf,IAAI,UAAU,EAAE,CAAC;QACf,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;SAAM,CAAC;QACN,yBAAyB;QACzB,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,QAAQ,CAAC;QACvD,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACjD,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;QAE5D,KAAK,GAAG,WAAW;aAChB,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;aACzD,IAAI,CAAC,GAAG,CAAC,CAAC;IACf,CAAC;IAED,OAAO;QACL,MAAM;QACN,KAAK;QACL,IAAI;QACJ,QAAQ;QACR,YAAY;QACZ,YAAY,EAAE,KAAK,CAAC,KAAK;QACzB,IAAI,EAAE,KAAK,CAAC,IAAI;KACjB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IAClD,OAAO,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AACpE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,OAAO,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { FullTextSearchOptions, SearchResult } from '../types/index.js';
|
|
2
|
+
import { FileRegistry } from '../indexing/file-registry.js';
|
|
3
|
+
import { FileCache } from '../cache/file-cache.js';
|
|
4
|
+
/**
|
|
5
|
+
* Full-text search implementation
|
|
6
|
+
*/
|
|
7
|
+
export declare class FullTextSearch {
|
|
8
|
+
private registry;
|
|
9
|
+
private fileCache;
|
|
10
|
+
constructor(registry: FileRegistry, fileCache: FileCache);
|
|
11
|
+
/**
|
|
12
|
+
* Performs full-text search across documentation
|
|
13
|
+
*/
|
|
14
|
+
search(options: FullTextSearchOptions): Promise<SearchResult[]>;
|
|
15
|
+
/**
|
|
16
|
+
* Scores a document based on query relevance
|
|
17
|
+
*/
|
|
18
|
+
private scoreDocument;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=fulltext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fulltext.d.ts","sourceRoot":"","sources":["../../src/search/fulltext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGnD;;GAEG;AACH,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,SAAS;gBADT,QAAQ,EAAE,YAAY,EACtB,SAAS,EAAE,SAAS;IAG9B;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IA0DrE;;OAEG;IACH,OAAO,CAAC,aAAa;CAyDtB"}
|