Skip to content

Commit 157414f

Browse files
author
Netdocs
committed
feat: make search plugin tag inclusion configurable
- Add 'include_tags' config option (defaults to true for backward compatibility) - When include_tags is false, tags are omitted from search index (empty array) - Reduces index size on sites with heavy tagging; allows users to toggle tag search - Add test to verify config option works correctly All 358 tests passing.
1 parent 5433a11 commit 157414f

2 files changed

Lines changed: 71 additions & 1 deletion

File tree

src/Netdocs.Plugins/SearchPlugin.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public sealed class SearchPlugin : IPlugin, IBuildHook
1818
private string _separator = DefaultSeparator;
1919
private IReadOnlyList<string> _pipeline = DefaultPipeline;
2020
private bool _stripBloatElements = true;
21+
private bool _includeTags = true;
2122

2223
public string Name => "search";
2324

@@ -40,6 +41,11 @@ public void Configure(IPluginContext ctx)
4041
// that inflate the index without adding search value. Defaults to true.
4142
if (opts.TryGetValue("strip_bloat_elements", out var strip) && strip is bool b)
4243
_stripBloatElements = b;
44+
45+
// `include_tags` controls whether tags are included in the search index. Tags are metadata
46+
// (not content) and can inflate the index. Defaults to true for backward compatibility.
47+
if (opts.TryGetValue("include_tags", out var incTags) && incTags is bool t)
48+
_includeTags = t;
4349
}
4450

4551
public async Task OnBuildCompleteAsync(SiteContext site, CancellationToken ct)
@@ -49,7 +55,7 @@ public async Task OnBuildCompleteAsync(SiteContext site, CancellationToken ct)
4955

5056
foreach (var page in site.Pages)
5157
{
52-
var tags = ExtractTags(page);
58+
var tags = _includeTags ? ExtractTags(page) : [];
5359
var (intro, sections) = SplitPage(parser, page, _stripBloatElements);
5460
docs.Add(new SearchDoc(page.Url, page.Title, intro, tags));
5561

tests/Netdocs.Core.Tests/SearchPluginTests.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,4 +177,68 @@ public void SeparatorAndPipeline_AreConfigurable()
177177
Assert.Equal("[\\s]+", cfg.GetProperty("separator").GetString());
178178
Assert.Equal(new[] { "trimmer" }, cfg.GetProperty("pipeline").EnumerateArray().Select(e => e.GetString()).ToArray());
179179
}
180+
181+
[Fact]
182+
public void IncludeTags_DefaultsToTrue()
183+
{
184+
var page = new Page
185+
{
186+
SourcePath = "",
187+
RelativePath = "index.md",
188+
Url = "test/",
189+
Title = "Test",
190+
HtmlContent = "<h1>Test</h1><p>Content</p>",
191+
PlainText = "Test Content",
192+
FrontMatter = new Dictionary<string, object?> { ["tags"] = new[] { "tag1", "tag2" } },
193+
};
194+
195+
var index = EmitIndex(page);
196+
var doc = index.GetProperty("docs").EnumerateArray().First(d => d.GetProperty("location").GetString() == "test/");
197+
var tags = doc.GetProperty("tags").EnumerateArray().Select(t => t.GetString()).ToList();
198+
199+
Assert.Equal(new[] { "tag1", "tag2" }, tags);
200+
}
201+
202+
[Fact]
203+
public void IncludeTags_CanBeDisabled()
204+
{
205+
var dir = Path.Combine(Path.GetTempPath(), "netdocs-search-" + Guid.NewGuid().ToString("N"));
206+
try
207+
{
208+
var plugin = new SearchPlugin();
209+
plugin.Configure(new FakeContext(new Dictionary<string, object?> { ["include_tags"] = false }));
210+
211+
var config = new SiteConfig { ProjectRoot = dir };
212+
var site = new SiteContext
213+
{
214+
Config = config,
215+
Options = new BuildOptions(),
216+
LoggerFactory = NullLoggerFactory.Instance,
217+
};
218+
var page = new Page
219+
{
220+
SourcePath = "",
221+
RelativePath = "index.md",
222+
Url = "test/",
223+
Title = "Test",
224+
HtmlContent = "<h1>Test</h1><p>Content</p>",
225+
PlainText = "Test Content",
226+
FrontMatter = new Dictionary<string, object?> { ["tags"] = new[] { "tag1", "tag2" } },
227+
};
228+
site.Pages.Add(page);
229+
230+
plugin.OnBuildCompleteAsync(site, CancellationToken.None).GetAwaiter().GetResult();
231+
var json = File.ReadAllText(Path.Combine(config.AbsoluteSiteDir, "search", "search_index.json"));
232+
var index = JsonDocument.Parse(json).RootElement;
233+
var doc = index.GetProperty("docs").EnumerateArray().First(d => d.GetProperty("location").GetString() == "test/");
234+
var tags = doc.GetProperty("tags").EnumerateArray().ToList();
235+
236+
// Tags should be empty when include_tags is false
237+
Assert.Empty(tags);
238+
}
239+
finally
240+
{
241+
if (Directory.Exists(dir)) Directory.Delete(dir, recursive: true);
242+
}
243+
}
180244
}

0 commit comments

Comments
 (0)