-
-
Notifications
You must be signed in to change notification settings - Fork 925
🐛 GritQL pattern export { $foo } from $source fails to match while export * from $source works #8828
Description
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: 0What 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.tsResult: 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:
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 $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
- I agree to follow Biome's Code of Conduct