Skip to content

Commit 0b573cd

Browse files
committed
fix(n8n): preserve root docs pages
1 parent 929110f commit 0b573cd

2 files changed

Lines changed: 65 additions & 2 deletions

File tree

nodes/Sourcey/sourcey/retrieval.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,8 +337,12 @@ export function relativeOutputPath(url: string, siteUrl: string): string {
337337
const sitePath = new URL(normalizeSiteUrl(siteUrl)).pathname.replace(/\/+$/, '');
338338
let parsedPath = new URL(url).pathname;
339339

340+
if (sitePath && parsedPath === sitePath) {
341+
return ROOT_OUTPUT_PATH;
342+
}
340343
if (sitePath && parsedPath.startsWith(`${sitePath}/`)) {
341344
parsedPath = parsedPath.slice(sitePath.length + 1);
345+
if (!parsedPath) return ROOT_OUTPUT_PATH;
342346
} else {
343347
parsedPath = parsedPath.replace(/^\/+/, '');
344348
}
@@ -661,10 +665,10 @@ function normalizeOutputPath(path: string): string {
661665
}
662666

663667
value = value.replace(/^\/+/, '').replace(/\/+$/, '');
664-
if (!value) return '';
668+
if (!value) return ROOT_OUTPUT_PATH;
665669
if (value.endsWith('.html')) value = value.slice(0, -5);
666670
else if (value.endsWith('.htm')) value = value.slice(0, -4);
667-
if (value === 'index') return '';
671+
if (value === ROOT_OUTPUT_PATH) return ROOT_OUTPUT_PATH;
668672
if (value.endsWith('/index')) value = value.slice(0, -'/index'.length);
669673
return value;
670674
}
@@ -723,6 +727,7 @@ const HEAD_RE = /<head\b.*?<\/head>/gis;
723727
const SCRIPT_STYLE_RE = /<(?:script|style)\b.*?>.*?<\/(?:script|style)>/gis;
724728
const TAG_RE = /<[^>]+>/g;
725729
const WHITESPACE_RE = /\s+/g;
730+
const ROOT_OUTPUT_PATH = 'index';
726731
const STOPWORDS = new Set([
727732
'a',
728733
'an',

test/sourcey-retrieval.test.mjs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,64 @@ Use Sourcey search-index.json and llms-full.txt to answer docs questions with ci
9494
);
9595
});
9696

97+
it('keeps root and index docs pages addressable', async () => {
98+
const pages = parseLlmsFullText(`### Home
99+
100+
Path: \`/index.html\`
101+
102+
Root page.
103+
`);
104+
105+
assert.equal(pages.index.title, 'Home');
106+
107+
const httpGet = fixtureHttpGet({
108+
'/reference/search-index.json': JSON.stringify([
109+
{
110+
title: 'Home',
111+
content: 'Landing docs page',
112+
url: '/reference/',
113+
tab: 'Guides',
114+
category: 'Pages',
115+
},
116+
]),
117+
'/reference/llms-full.txt': `### Home
118+
119+
Path: \`/reference/index.html\`
120+
121+
Full landing page from llms-full.
122+
`,
123+
});
124+
125+
const results = await searchSourceyDocs({
126+
httpGet,
127+
siteUrl: SITE_URL,
128+
query: 'landing docs',
129+
topK: 1,
130+
});
131+
132+
assert.equal(results[0].path, 'index');
133+
assert.equal(results[0].url, 'https://docs.example.com/reference/');
134+
135+
const context = await retrieveSourceyContext({
136+
httpGet,
137+
siteUrl: SITE_URL,
138+
query: 'landing docs',
139+
topK: 1,
140+
maxContextChars: 1000,
141+
});
142+
143+
assert.match(context.context, /Full landing page from llms-full/);
144+
145+
const fetched = await fetchSourceyPage({
146+
httpGet,
147+
siteUrl: SITE_URL,
148+
pathOrUrl: SITE_URL,
149+
});
150+
151+
assert.equal(fetched.path, 'index');
152+
assert.equal(fetched.pageContent, 'Full landing page from llms-full.');
153+
});
154+
97155
it('fetches a page from llms-full or falls back to HTML', async () => {
98156
const fromLlms = await fetchSourceyPage({
99157
httpGet: fixtureHttpGet({

0 commit comments

Comments
 (0)