Environment information
Details
CLI:
Version: 2.3.11
Color support: true
Platform:
CPU Architecture: aarch64
OS: macos
Environment:
BIOME_LOG_PATH: unset
BIOME_LOG_PREFIX_NAME: unset
BIOME_CONFIG_PATH: unset
BIOME_THREADS: unset
NO_COLOR: unset
TERM: xterm-256color
JS_RUNTIME_VERSION: v24.12.0
JS_RUNTIME_NAME: node
NODE_PACKAGE_MANAGER: npm/11.6.2
Biome Configuration:
Status: Loaded successfully
Formatter enabled: true
Linter enabled: true
Assist enabled: true
VCS enabled: true
Workspace:
Open Documents: 0
What happened?
GritQL patterns for named exports (export { $foo } from $source) fail to match export statements, while the structurally similar star export pattern (export * from $source) works correctly.
Reproduction steps
- Create a directory and navigate to it:
mkdir -p biome_repro && cd biome_repro
- Create a GritQL rule file (
rule.grit):
`export { $foo } from $source` where {
$source <: r"^['\"]\.\.?/.*",
register_diagnostic(span=$source, message="Found relative export")
}
- Create
biome.json:
{
"$schema": "https://biomejs.dev/schemas/2.3.11/schema.json",
"plugins": ["./rule.grit"],
"linter": { "enabled": true, "rules": { "recommended": false } }
}
- Create a test file (
repro.ts):
export { foo } from "../../deep/path";
- Run Biome lint:
npx @biomejs/biome lint repro.ts
Result: No diagnostic is emitted. ❌
Comparison with working patterns
| Pattern |
Code |
Result |
export * from $source |
export * from "../../deep/path"; |
✅ Matches |
import $name from $source |
import foo from "../../deep/path"; |
✅ Matches |
export { $foo } from $source |
export { foo } from "../../deep/path"; |
❌ No match |
Unit test reproduction (Biome source)
I verified this bug in the Biome source code by adding a test to crates/biome_grit_patterns/tests/quick_test.rs:
#[test]
fn test_export_named_from_deep_path() {
let parse_grit_result = parse_grit(
r#"`export { $foo } from $source` where {
$source <: r"^['\"]\.\.?/.*"
}"#,
);
// ... setup code ...
let body = r#"export { foo } from "../../deep/path";"#;
let parsed = parse(body, JsFileSource::js_module(), JsParserOptions::default());
let file = GritTargetFile::new("test.js", parsed.into());
let GritQueryResult { effects, .. } = query.execute(file).expect("could not execute query");
// THIS FAILS - effects is empty
assert!(!effects.is_empty(), "Expected match for export { foo } from");
}
Investigation findings
-
Mapping exists: JsExportNamedFromClause is correctly mapped in generated_mappings.rs.
-
Snippet parsing issue: The pattern export { $foo } from $source gets incorrectly parsed as JS_OBJECT_MEMBER_LIST or JSX_CHILD_LIST instead of JS_EXPORT_NAMED_FROM_CLAUSE.
-
Likely cause: The snippet_context_strings() in crates/biome_grit_patterns/src/grit_target_language/js_target_language.rs may not provide adequate context for parsing export { ... } from ... statements.
Expected result
The GritQL pattern export { $foo } from $source should match the code export { foo } from "../../deep/path"; and emit a diagnostic, just like export * from $source does for export * from "../../deep/path";.
Code of Conduct
Environment information
Details
What happened?
GritQL patterns for named exports (
export { $foo } from $source) fail to match export statements, while the structurally similar star export pattern (export * from $source) works correctly.Reproduction steps
rule.grit):biome.json:{ "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", "plugins": ["./rule.grit"], "linter": { "enabled": true, "rules": { "recommended": false } } }repro.ts):Result: No diagnostic is emitted. ❌
Comparison with working patterns
export * from $sourceexport * from "../../deep/path";import $name from $sourceimport foo from "../../deep/path";export { $foo } from $sourceexport { foo } from "../../deep/path";Unit test reproduction (Biome source)
I verified this bug in the Biome source code by adding a test to
crates/biome_grit_patterns/tests/quick_test.rs:Investigation findings
Mapping exists:
JsExportNamedFromClauseis correctly mapped ingenerated_mappings.rs.Snippet parsing issue: The pattern
export { $foo } from $sourcegets incorrectly parsed asJS_OBJECT_MEMBER_LISTorJSX_CHILD_LISTinstead ofJS_EXPORT_NAMED_FROM_CLAUSE.Likely cause: The
snippet_context_strings()incrates/biome_grit_patterns/src/grit_target_language/js_target_language.rsmay not provide adequate context for parsingexport { ... } from ...statements.Expected result
The GritQL pattern
export { $foo } from $sourceshould match the codeexport { foo } from "../../deep/path";and emit a diagnostic, just likeexport * from $sourcedoes forexport * from "../../deep/path";.Code of Conduct