Skip to content

chore: combine attribute impl#9950

Merged
dyc3 merged 1 commit intobiomejs:mainfrom
Netail:chore/combine-attribute-impl
Apr 13, 2026
Merged

chore: combine attribute impl#9950
dyc3 merged 1 commit intobiomejs:mainfrom
Netail:chore/combine-attribute-impl

Conversation

@Netail
Copy link
Copy Markdown
Member

@Netail Netail commented Apr 12, 2026

Summary

Seems like there were 2 files for attribute implementation extensions, combined them

Test Plan

Docs

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 12, 2026

⚠️ No Changeset found

Latest commit: 72b2639

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions github-actions Bot added A-Parser Area: parser L-HTML Language: HTML and super languages labels Apr 12, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 12, 2026

Walkthrough

This change refactors HTML attribute parsing helpers in the Biome HTML syntax module. The implementation of five extension methods—string_value() on AnyHtmlAttributeInitializer, find_by_name() on HtmlAttributeList, value() on HtmlAttribute, and token_text() and token_text_trimmed() on HtmlAttributeName—is migrated from attr_ext.rs to attribute_ext.rs. The module declaration in lib.rs is updated accordingly by removing the attr_ext module reference. The public API remains unchanged; only the file organisation and module structure are modified.

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: combining two attribute implementation files into one.
Description check ✅ Passed The description clearly explains that two attribute implementation files were combined, which matches the actual changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/biome_html_syntax/src/attribute_ext.rs`:
- Around line 12-17: The HtmlString arm currently turns a missing/invalid token
into Some("") by calling unwrap_or_default; instead preserve the absence by
returning None when value_token() is None. Replace the unwrap_or_default usage
in the Self::HtmlString branch so that you map the token with
value_token().map(|token| inner_string_text(&token).into()) and let that Option
propagate (i.e., remove the unwrap_or_default), ensuring the expression yields
None when the token is missing.
- Around line 7-66: Add unit/integration tests that exercise the moved helpers:
AnyHtmlAttributeInitializer::string_value,
AnyHtmlAttributeInitializer::as_static_value (where applicable),
HtmlAttributeList::find_by_name, HtmlAttribute::value,
HtmlAttributeName::token_text and token_text_trimmed; cover both positive cases
(attributes with plain strings, quoted strings, single-text expressions, and
name lookup matches) and negative cases (missing initializer, non-string
initializers, missing attribute name matches, and tokens that require trimming),
and use snapshot/assertion-based checks to lock the current behavior after the
refactor.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 24ca8afb-f8da-4a39-abbc-0c54e25d625b

📥 Commits

Reviewing files that changed from the base of the PR and between 9956f1d and 72b2639.

📒 Files selected for processing (3)
  • crates/biome_html_syntax/src/attr_ext.rs
  • crates/biome_html_syntax/src/attribute_ext.rs
  • crates/biome_html_syntax/src/lib.rs
💤 Files with no reviewable changes (2)
  • crates/biome_html_syntax/src/lib.rs
  • crates/biome_html_syntax/src/attr_ext.rs

Comment on lines 7 to +66
impl AnyHtmlAttributeInitializer {
/// Returns the string value of the attribute, if available, without quotes.
pub fn string_value(&self) -> Option<Text> {
match self {
Self::HtmlAttributeSingleTextExpression(text) => text.expression().ok()?.string_value(),
Self::HtmlString(string) => Some(
string
.value_token()
.map(|token| inner_string_text(&token).into())
.unwrap_or_default(),
),
}
}

pub fn as_static_value(&self) -> Option<StaticValue> {
match self {
Self::HtmlAttributeSingleTextExpression(_) => None,
Self::HtmlString(value) => Some(StaticValue::String(value.value_token().ok()?)),
}
}
}

impl HtmlAttributeList {
pub fn find_by_name(&self, name_to_lookup: &str) -> Option<HtmlAttribute> {
self.iter().find_map(|attribute| {
if let AnyHtmlAttribute::HtmlAttribute(attribute) = attribute
&& let Ok(name) = attribute.name()
&& name.value_token().ok()?.text_trimmed() == name_to_lookup
{
return Some(attribute);
}
None
})
}
}

impl HtmlAttribute {
/// Extracts the value from an attribute's initializer.
///
/// Returns `None` if the attribute has no initializer or the value cannot be extracted.
pub fn value(&self) -> Option<Text> {
self.initializer()
.and_then(|init| init.value().ok())
.and_then(|value| value.string_value())
}
}

impl HtmlAttributeName {
/// Returns the token text of the attribute name.
pub fn token_text(&self) -> Option<TokenText> {
self.value_token().ok().map(|token| token.token_text())
}

/// Returns the trimmed token text of the attribute name.
pub fn token_text_trimmed(&self) -> Option<TokenText> {
self.value_token()
.ok()
.map(|token| token.token_text_trimmed())
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Please add coverage for the moved attribute helper APIs.

This refactor moves core helper behaviour, but no accompanying tests are included in this PR. Even for file consolidation, we should lock behaviour with tests for string_value, find_by_name, value, and token_text(_trimmed) paths.

As per coding guidelines: **/*.{rs,ts,tsx,js}: “All code changes MUST include appropriate tests: lint rules require snapshot tests in 'tests/specs/{group}/{rule}/', formatters require snapshot tests with valid/invalid cases, parsers require test files covering valid and error cases, and bug fixes require tests that reproduce and validate the fix.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_html_syntax/src/attribute_ext.rs` around lines 7 - 66, Add
unit/integration tests that exercise the moved helpers:
AnyHtmlAttributeInitializer::string_value,
AnyHtmlAttributeInitializer::as_static_value (where applicable),
HtmlAttributeList::find_by_name, HtmlAttribute::value,
HtmlAttributeName::token_text and token_text_trimmed; cover both positive cases
(attributes with plain strings, quoted strings, single-text expressions, and
name lookup matches) and negative cases (missing initializer, non-string
initializers, missing attribute name matches, and tokens that require trimming),
and use snapshot/assertion-based checks to lock the current behavior after the
refactor.

Comment on lines +12 to +17
Self::HtmlString(string) => Some(
string
.value_token()
.map(|token| inner_string_text(&token).into())
.unwrap_or_default(),
),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Avoid masking missing/invalid string tokens with an empty default.

Line 16 currently converts token access failures into Some(""), which can blur parse-error states and “empty value” states. Returning None here is safer and aligns with the method contract (“if available”).

Suggested fix
-            Self::HtmlString(string) => Some(
-                string
-                    .value_token()
-                    .map(|token| inner_string_text(&token).into())
-                    .unwrap_or_default(),
-            ),
+            Self::HtmlString(string) => string
+                .value_token()
+                .ok()
+                .map(|token| inner_string_text(&token).into()),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Self::HtmlString(string) => Some(
string
.value_token()
.map(|token| inner_string_text(&token).into())
.unwrap_or_default(),
),
Self::HtmlString(string) => string
.value_token()
.ok()
.map(|token| inner_string_text(&token).into()),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_html_syntax/src/attribute_ext.rs` around lines 12 - 17, The
HtmlString arm currently turns a missing/invalid token into Some("") by calling
unwrap_or_default; instead preserve the absence by returning None when
value_token() is None. Replace the unwrap_or_default usage in the
Self::HtmlString branch so that you map the token with value_token().map(|token|
inner_string_text(&token).into()) and let that Option propagate (i.e., remove
the unwrap_or_default), ensuring the expression yields None when the token is
missing.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 12, 2026

Merging this PR will not alter performance

✅ 67 untouched benchmarks
⏩ 189 skipped benchmarks1


Comparing Netail:chore/combine-attribute-impl (72b2639) with main (9956f1d)

Open in CodSpeed

Footnotes

  1. 189 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Copy link
Copy Markdown
Contributor

@dyc3 dyc3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah this probably happened when merging main and next at some point.

approving tentatively, but I want to merge the existing main into next first. #9945 is already quite monstrous.

string
.value_token()
.map(|token| inner_string_text(&token).into())
.unwrap_or_default(),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.unwrap_or_default(),

Copy link
Copy Markdown
Member Author

@Netail Netail Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that does change a bit of logic, which is perhaps out of scope for this PR. It seems that it currently always returns a Some() then if there's not inner text it just returns an Some(""). But yeah could change some stuff around

@dyc3 dyc3 merged commit 0a60ce0 into biomejs:main Apr 13, 2026
17 checks passed
@Netail Netail deleted the chore/combine-attribute-impl branch April 14, 2026 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Parser Area: parser L-HTML Language: HTML and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants