Skip to content
Open
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
25 changes: 25 additions & 0 deletions .changeset/blue-parts-lie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
"@biomejs/biome": patch
---

Fixed [#8233](https://github.com/biomejs/biome/issues/8233), where Biome CLI in
stdin mode didn't work correctly when handling files in projects with nested
configurations. For example, with the following structure,
`--stdin-file-path=subdirectory/...` would not use the nested configuration in
`subdirectory/biome.json`:

```
├── biome.json
└── subdirectory
├── biome.json
└── lib.js
```

```shell
biome format --write --stdin-file-path=subdirectory/lib.js < subdirectory/lib.js
```

Now, the nested configuration is correctly picked up and applied.

In addition, Biome now shows a warning if `--stdin-file-path` is provided but
that path is ignored and therefore not formatted or fixed.
4 changes: 1 addition & 3 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,7 @@ jobs:
- name: Build Biome debug binary
run: cargo build --bin biome
- name: Run tests
run: |
cd e2e-tests
sh test-all.sh
run: ./e2e-tests/test-all.sh

documentation:
name: Documentation
Expand Down
1 change: 1 addition & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"!**/undefined",
"!**/benchmark/target",
"!**/benches",
"!!**/e2e-tests",
"!!**/target",
"!!.cargo"
]
Expand Down
10 changes: 9 additions & 1 deletion crates/biome_cli/src/execute/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,15 @@ pub fn execute_mode(

// don't do any traversal if there's some content coming from stdin
if let Some(stdin) = execution.as_stdin_file() {
let biome_path = BiomePath::new(stdin.as_path());
// Biome path must starts_with(the project directory), which will have been
// joined to workdir. Otherwise we won't find nested settings.
let working_dir = session
.app
.workspace
.fs()
.working_directory()
.unwrap_or_default();
let biome_path = BiomePath::new(working_dir.join(stdin.as_path()));
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.

This operation might not be safe, because stdin.as_path might be an absolute path. We should check it before running the join operation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Almost every path library I can think of, including camino, replaces the original path when you .join(absolute).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Well there may be an edge case where the working dir has a symlink in it somewhere and someone passes an absolute path that resolves to the same file ultimately, but does not appear to be inside any project. But I am not sure we care.

return std_in::run(
session,
project_key,
Expand Down
9 changes: 9 additions & 0 deletions crates/biome_cli/src/execute/std_in.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ pub(crate) fn run<'a>(

if file_features.is_ignored() {
console.append(markup! {{content}});
// Write error last because files may generally be long
console.error(markup! {
<Warn>"The content was not formatted because the path `"{biome_path.as_str()}"` is ignored."</Warn>
});
return Ok(());
}

Expand Down Expand Up @@ -99,6 +103,7 @@ pub(crate) fn run<'a>(
console.append(markup! {
{content}
});
// Write error last because files may generally be long
console.error(markup! {
<Warn>"The content was not formatted because the formatter is currently disabled."</Warn>
});
Expand Down Expand Up @@ -130,6 +135,10 @@ pub(crate) fn run<'a>(

if file_features.is_ignored() {
console.append(markup! {{content}});
// Write error last because files may generally be long
console.error(markup! {
<Warn>"The content was not fixed because the path `"{biome_path.as_str()}"` is ignored."</Warn>
});
return Ok(());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ function f() {var x=1; return{x}} class Foo {}
```block
function f() {var x=1; return{x}} class Foo {}
```

```block
The content was not fixed because the path `mock.cc` is ignored.
```
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ function f() {return{}}
```block
function f() {return{}}
```

```block
The content was not formatted because the path `mock.cc` is ignored.
```
2 changes: 1 addition & 1 deletion e2e-tests/relative-path-ignore-file/biome.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"root": false,
"root": true,
"files": {
"includes": ["**", "!file.js"]
},
Expand Down
2 changes: 1 addition & 1 deletion e2e-tests/relative-path/biome.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"root": false,
"root": true,
"files": {
"includes": ["**"]
},
Expand Down
5 changes: 5 additions & 0 deletions e2e-tests/stdin-nested-config/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let x = 5;

function indent() {
return x;
}
5 changes: 5 additions & 0 deletions e2e-tests/stdin-nested-config/app.js.formatted
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let x = 5;

function indent() {
return x;
}
16 changes: 16 additions & 0 deletions e2e-tests/stdin-nested-config/biome.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"root": true,
"vcs": {
"enabled": false
},
"files": {
"ignoreUnknown": false,
// Include .js recursively, but not .ts
"includes": ["**/biome.jsonc", "**/*.js"]
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 4
}
}
1 change: 1 addition & 0 deletions e2e-tests/stdin-nested-config/donotformat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
let x = 10;
12 changes: 12 additions & 0 deletions e2e-tests/stdin-nested-config/subdirectory/biome.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"root": false,
"extends": "//",
"files": {
// This should be relative to the location of this config file, so we should not touch root/donotformat.ts
"includes": ["*.ts"]
},
"formatter": {
"indentStyle": "space",
"indentWidth": 2
}
}
5 changes: 5 additions & 0 deletions e2e-tests/stdin-nested-config/subdirectory/lib.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let y = 65;

function indent() {
return y;
}
5 changes: 5 additions & 0 deletions e2e-tests/stdin-nested-config/subdirectory/lib.js.formatted
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let y = 65;

function indent() {
return y;
}
5 changes: 5 additions & 0 deletions e2e-tests/stdin-nested-config/subdirectory/typed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let y = 65;

function indent() {
return y;
}
5 changes: 5 additions & 0 deletions e2e-tests/stdin-nested-config/subdirectory/typed.ts.formatted
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let y = 65;

function indent() {
return y;
}
28 changes: 28 additions & 0 deletions e2e-tests/stdin-nested-config/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail

TEMP=$(mktemp)
trap 'rm -f $TEMP' EXIT

biome() {
cargo run --bin biome -- "$@"
}

STATUS=0
diff_stdin_filepath() {
biome format --stdin-file-path="$1" < "$1" > "$TEMP"
if ! git diff --no-index "$1.formatted" "$TEMP"; then
STATUS=1
fi
}

diff_stdin_filepath app.js
diff_stdin_filepath subdirectory/lib.js
diff_stdin_filepath subdirectory/typed.ts

biome format --stdin-file-path="donotformat.ts" < "donotformat.ts" > "$TEMP"
if ! git diff --no-index "donotformat.ts" "$TEMP"; then
STATUS=1
fi

exit $STATUS
31 changes: 27 additions & 4 deletions e2e-tests/test-all.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
#!/bin/sh
#!/usr/bin/env bash

# Usage:
# ./test-all.sh
# ./test-all.sh stdin # to filter tests by name

set -eu

# Change to the script's directory
cd "$(dirname "$0")"

# Glob matcher
if [[ -z "${1:-}" ]]; then FILTER="*"; else FILTER="*$1*"; fi

redecho() {
echo -e "\033[1;31m$1\033[0m"
}

bail() {
redecho "Error: $1"
exit 1
}

for x in *; do
if test -d "$x"; then
if [[ "$x" != $FILTER ]]; then
echo "Skipping $x"
continue
fi
echo "Testing $x..."
cd "$x"
sh test.sh
cd ..
pushd "$x" > /dev/null
bash test.sh || bail "Test failed: $x. To re-run: $0 $x"
popd > /dev/null
fi
done