Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions changelog.d/unreleased/2103.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 2103
affected:
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.Markup.cs
- tests/CodeIndex.Tests/SymbolExtractorTests.cs
---

## English

- **HTML class attributes are indexed as individual references (#2103)** — `class` and `className` values now split on whitespace so utility classes such as `btn`, `mx-2`, and Tailwind variants can be searched individually.

## 日本語

- **HTML の class 属性を個別の reference としてインデックスするようになりました (#2103)** — `class` と `className` の値を空白で分割し、`btn`、`mx-2`、Tailwind の variant などを個別に検索できるようにしました。
16 changes: 16 additions & 0 deletions changelog.d/unreleased/2603.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
category: fixed
issues:
- 2603
affected:
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs
- tests/CodeIndex.Tests/SymbolExtractorTests.cs
---

## English

- **Rust trait associated type defaults are emitted again (#2603)** — associated type defaults in Rust `trait` bodies now scan the existing `protocol` trait symbols, restoring `property` symbols for declarations such as `type Output = ();`.

## 日本語

- **Rust trait の associated type default を再び出力するようになりました (#2603)** — Rust の `trait` 本体にある associated type default が既存の `protocol` trait symbol を走査するようになり、`type Output = ();` などの `property` symbol が復元されました。
11 changes: 11 additions & 0 deletions src/CodeIndex/Indexer/Symbols/SymbolExtractor.Markup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,11 @@ private static List<SymbolRecord> ExtractHtmlSymbols(long fileId, string[] lines
emitKind = "property";
emittedNames = [attrValue.Trim()];
}
else if (attrNameLower is "class" or "classname")
{
emitKind = "reference";
emittedNames = EnumerateHtmlClassNames(attrValue).ToList();
}
else if (attrNameLower == "name" && tagNameLower == "slot")
{
var slotName = attrValue.Trim();
Expand Down Expand Up @@ -310,6 +315,12 @@ private static List<SymbolRecord> ExtractHtmlSymbols(long fileId, string[] lines
return symbols;
}

private static IEnumerable<string> EnumerateHtmlClassNames(string value)
{
foreach (var token in value.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries))
yield return token;
}

private static bool IsHtmlSemanticStateAttributeName(string attrNameLower)
{
return (attrNameLower.StartsWith("data-", StringComparison.Ordinal) ||
Expand Down
4 changes: 2 additions & 2 deletions src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10038,7 +10038,7 @@ private static bool IsCppTemplateSpecializationSymbol(
private static void ExtractRustAssociatedTypeDefaultSymbols(long fileId, string[] lines, string[] structuralLines, List<SymbolRecord> symbols)
{
var traits = symbols
.Where(symbol => symbol.Kind == "interface"
.Where(symbol => symbol.Kind is "interface" or "protocol"
&& symbol.BodyStartLine is > 0
&& symbol.BodyEndLine is > 0)
.OrderBy(symbol => symbol.StartLine)
Expand Down Expand Up @@ -10070,7 +10070,7 @@ private static void ExtractRustAssociatedTypeDefaultSymbols(long fileId, string[
StartColumn = nameGroup.Index,
EndLine = lineNumber,
Signature = lines[lineIndex].Trim(),
ContainerKind = trait.Kind,
ContainerKind = "interface",
ContainerName = trait.Name,
ContainerQualifiedName = trait.ContainerQualifiedName,
Visibility = match.Groups["visibility"].Success ? match.Groups["visibility"].Value : null,
Expand Down
27 changes: 27 additions & 0 deletions tests/CodeIndex.Tests/SymbolExtractorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,33 @@ private void Load() { }
Assert.Contains(symbols, symbol => symbol.Kind == "function" && symbol.Name == "Load");
}

[Fact]
public void Extract_HtmlClassAttributes_IndexesIndividualClassReferences()
{
const string content = """
<div class="btn btn-primary mx-2 md:flex hover:bg-red-500 [&>*]:mt-2"></div>
<span className='inline-flex items-center'></span>
<section class=" "></section>
""";

var symbols = SymbolExtractor.Extract(1, "html", content);
var classReferences = symbols
.Where(symbol => symbol.Kind == "reference")
.Select(symbol => (symbol.Name, symbol.Line))
.ToArray();

Assert.Contains(("btn", 1), classReferences);
Assert.Contains(("btn-primary", 1), classReferences);
Assert.Contains(("mx-2", 1), classReferences);
Assert.Contains(("md:flex", 1), classReferences);
Assert.Contains(("hover:bg-red-500", 1), classReferences);
Assert.Contains(("[&>*]:mt-2", 1), classReferences);
Assert.Contains(("inline-flex", 2), classReferences);
Assert.Contains(("items-center", 2), classReferences);
Assert.DoesNotContain(classReferences, symbol => string.IsNullOrWhiteSpace(symbol.Name));
Assert.DoesNotContain(("btn btn-primary mx-2 md:flex hover:bg-red-500 [&>*]:mt-2", 1), classReferences);
}

[Theory]
[InlineData("javascript")]
[InlineData("typescript")]
Expand Down
Loading