Skip to content

feat(js-embed): detect embedded GraphQL/CSS via content comments#9581

Closed
praetoros wants to merge 2 commits intobiomejs:nextfrom
praetoros:feat/embed-graphql-content-comment-main
Closed

feat(js-embed): detect embedded GraphQL/CSS via content comments#9581
praetoros wants to merge 2 commits intobiomejs:nextfrom
praetoros:feat/embed-graphql-content-comment-main

Conversation

@praetoros
Copy link
Copy Markdown

Summary

  • Added support for #graphql and #css comments on the first line of untagged template literals as embedded language markers.
  • Added support for /* GraphQL */ and /* CSS */ block comments before template literals as embedded language markers.
  • This enables embedded formatting and linting for codebases that use comment-based markers instead of tagged templates (e.g. for as const type inference compatibility with tools like graphql-codegen).

Closes #9511

AI assistance notice

This PR was written primarily by Claude Code.

Details

The implementation extends the existing embed detection system with a new TemplateComment detector and ContentComment tag kind, following the same patterns as TemplateTag/TemplateExpression. Detection is zero-cost for tagged templates (early return) and lightweight for untagged templates (string prefix checks, no allocations). Gated behind experimentalEmbeddedSnippetsEnabled.

Supported patterns:

// #graphql content comment
const query = `#graphql
  query foo {
    bar
  }
` as const;

// /* GraphQL */ block comment
const query2 = /* GraphQL */`
  query foo {
    bar
  }
`;

Test plan

  • New CLI test should_detect_graphql_with_content_comment covering both #graphql and /* GraphQL */ patterns.
  • New Prettier spec test inline-comment-tag.js for formatter comparison.
  • All existing embedded language tests pass (7 CLI, 9 formatter, 18 service).
  • Verify no regressions in CI.

Support `#graphql` and `#css` comments on the first line of untagged
template literals, and `/* GraphQL */` / `/* CSS */` block comments
before template literals, as markers for embedded language detection.

This enables embedded formatting and linting for codebases that use
comment-based markers instead of tagged templates (e.g. for `as const`
type inference compatibility with tools like graphql-codegen).

Closes biomejs#9511

> This PR was written primarily by Claude Code.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 22, 2026

🦋 Changeset detected

Latest commit: c482f26

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 14 packages
Name Type
@biomejs/biome Minor
@biomejs/cli-win32-x64 Minor
@biomejs/cli-win32-arm64 Minor
@biomejs/cli-darwin-x64 Minor
@biomejs/cli-darwin-arm64 Minor
@biomejs/cli-linux-x64 Minor
@biomejs/cli-linux-arm64 Minor
@biomejs/cli-linux-x64-musl Minor
@biomejs/cli-linux-arm64-musl Minor
@biomejs/wasm-web Minor
@biomejs/wasm-bundler Minor
@biomejs/wasm-nodejs Minor
@biomejs/backend-jsonrpc Patch
@biomejs/js-api Major

Not sure what this means? Click here to learn what changesets are.

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

@github-actions github-actions Bot added A-CLI Area: CLI A-Project Area: project A-Formatter Area: formatter L-JavaScript Language: JavaScript and super languages labels Mar 22, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 22, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 56effcc1-05c7-4acf-be6c-703bf02b781b

📥 Commits

Reviewing files that changed from the base of the PR and between ac76c3f and c482f26.

📒 Files selected for processing (1)
  • .changeset/feat-embed-graphql-content-comment.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/feat-embed-graphql-content-comment.md

Walkthrough

This PR adds comment-based detection for embedded GraphQL and CSS in JavaScript template literals. It introduces TemplateTagKind::ContentComment, an EmbedDetector::TemplateComment variant, expands JS detector registry entries, and updates JS file handling to detect #graphql/#css first-line markers and preceding /* GraphQL *///* CSS */ block comments. Tests and Prettier snapshots for the new detection cases were added and a changeset documents the feature.

Possibly related PRs

Suggested labels

A-Parser

Suggested reviewers

  • ematipico
  • dyc3
  • Netail
  • siketyan
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding support for detecting embedded GraphQL/CSS via content comments (both #graphql and /* GraphQL */ styles) in template literals.
Description check ✅ Passed The description is well-related to the changeset, clearly explaining the new comment-based embedded language detection feature, supported patterns, implementation details, and test coverage.

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

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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Tip

You can make CodeRabbit's review stricter and more nitpicky using the `assertive` profile, if that's what you prefer.

Change the reviews.profile setting to assertive to make CodeRabbit's nitpick more issues in your PRs.

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: 1

🤖 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_service/src/file_handlers/javascript.rs`:
- Around line 670-679: The detection logic in detect_content_comment_tag is
case-sensitive while detect_block_comment_tag uses eq_ignore_ascii_case, causing
mismatched behavior (e.g., "#GraphQL" not detected but "/* graphql */" is);
update detect_content_comment_tag to perform case-insensitive comparisons (e.g.,
use language_id.eq_ignore_ascii_case(...)) for the same set of languages
(graphql, css) or, if the difference is intentional, add a concise comment in
detect_content_comment_tag explaining why inline tags are case-sensitive to
avoid confusion; reference detect_content_comment_tag and
detect_block_comment_tag when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0a20d6ed-d201-4652-ad5f-516327b65d9a

📥 Commits

Reviewing files that changed from the base of the PR and between f5a4833 and ac76c3f.

⛔ Files ignored due to path filters (2)
  • crates/biome_cli/tests/snapshots/main_cases_javascript/should_detect_graphql_with_content_comment.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_formatter/tests/specs/prettier/js/multiparser-graphql/inline-comment-tag.js.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (7)
  • crates/biome_cli/tests/cases/javascript.rs
  • crates/biome_js_formatter/tests/specs/prettier/js/multiparser-graphql/inline-comment-tag.js
  • crates/biome_js_formatter/tests/specs/prettier/js/multiparser-graphql/inline-comment-tag.js.prettier-snap
  • crates/biome_service/src/embed/detector.rs
  • crates/biome_service/src/embed/registry.rs
  • crates/biome_service/src/embed/types.rs
  • crates/biome_service/src/file_handlers/javascript.rs

Comment on lines +670 to +679
fn detect_content_comment_tag(text: &str) -> Option<TemplateTagKind> {
let trimmed = text.trim_start_matches(['\n', '\r', ' ', '\t']);
let rest = trimmed.strip_prefix('#')?;
let language_id = rest.split(|c: char| c.is_whitespace()).next()?;
match language_id {
"graphql" => Some(TemplateTagKind::ContentComment { language: "graphql" }),
"css" => Some(TemplateTagKind::ContentComment { language: "css" }),
_ => None,
}
}
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

Inconsistent case sensitivity between inline and block comment detection.

detect_content_comment_tag uses case-sensitive matching ("graphql", "css"), whilst detect_block_comment_tag uses eq_ignore_ascii_case. This means:

  • `#GraphQL ...` → not detected
  • /* graphql */ → detected

Is this intentional? If so, consider adding a brief comment explaining the difference. If not, you may want to align them.

🔧 Suggested fix for consistent case-insensitive matching
 fn detect_content_comment_tag(text: &str) -> Option<TemplateTagKind> {
     let trimmed = text.trim_start_matches(['\n', '\r', ' ', '\t']);
     let rest = trimmed.strip_prefix('#')?;
     let language_id = rest.split(|c: char| c.is_whitespace()).next()?;
-    match language_id {
-        "graphql" => Some(TemplateTagKind::ContentComment { language: "graphql" }),
-        "css" => Some(TemplateTagKind::ContentComment { language: "css" }),
-        _ => None,
+    if language_id.eq_ignore_ascii_case("graphql") {
+        Some(TemplateTagKind::ContentComment { language: "graphql" })
+    } else if language_id.eq_ignore_ascii_case("css") {
+        Some(TemplateTagKind::ContentComment { language: "css" })
+    } else {
+        None
     }
 }

Also applies to: 710-713

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

In `@crates/biome_service/src/file_handlers/javascript.rs` around lines 670 - 679,
The detection logic in detect_content_comment_tag is case-sensitive while
detect_block_comment_tag uses eq_ignore_ascii_case, causing mismatched behavior
(e.g., "#GraphQL" not detected but "/* graphql */" is); update
detect_content_comment_tag to perform case-insensitive comparisons (e.g., use
language_id.eq_ignore_ascii_case(...)) for the same set of languages (graphql,
css) or, if the difference is intentional, add a concise comment in
detect_content_comment_tag explaining why inline tags are case-sensitive to
avoid confusion; reference detect_content_comment_tag and
detect_block_comment_tag when making the change.

Copy link
Copy Markdown
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

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

Thank you for the PR. I'm not totally sure this is the best way to propose something. I see that your discussion didn't gain any feedback, and maybe the PR could help. Nothing wrong with that.

Here's what I think you should improve:

  • the original discussion assumes we know what you're talking about. That's not the case.
  • the PR fails to provide the minimal business requirements that should help reviewers to understand the validity of the feature
  • the PR description it's just AI slop of technicalities that don't play any role in the review. In fact even the AI bot doesn't know what's correct or what's wrong.
  • still, there are zero links to the source of this feature. I spent 5min looking for something, and I couldn't find anything. I don't want to do that. If you propose something, the least you can do is to send us directly to the proper docs

@ematipico ematipico closed this Mar 22, 2026
@praetoros
Copy link
Copy Markdown
Author

praetoros commented Mar 22, 2026

Hey, firstly, sorry for the slop, this was still WIP (I'm testing it at the moment), but I figured I would put it here since then I'm at least contributing a little rather than asking others to do it on my behalf.

When I have some more time, I'll do another pass over to fill in the holes you have pointed out in how I have suggested/submitted this.

When it comes to the body of the PR, I do not have any rust experience, so I have clearly outlined everything here was done by AI as the contributing.md requests. To my understanding the case (embedded detection based off comments) and the technical description of the changes present line up.

Sources:

Why the String.raw workaround doesnt work:
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CLI Area: CLI A-Formatter Area: formatter A-Project Area: project L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants