Skip to content

feat(oxfmt): oxfmt --init#16703

Closed
Boshen wants to merge 1 commit intomainfrom
12-10-feat_oxfmt_oxfmt_--init_
Closed

feat(oxfmt): oxfmt --init#16703
Boshen wants to merge 1 commit intomainfrom
12-10-feat_oxfmt_oxfmt_--init_

Conversation

@Boshen
Copy link
Copy Markdown
Member

@Boshen Boshen commented Dec 10, 2025

closes #16622

Copilot AI review requested due to automatic review settings December 10, 2025 14:51
@github-actions github-actions bot added A-cli Area - CLI A-formatter Area - Formatter C-enhancement Category - New feature or request labels Dec 10, 2025
@Boshen Boshen force-pushed the 12-10-feat_oxfmt_oxfmt_--init_ branch from 6d49dbd to d692118 Compare December 10, 2025 14:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements the --init flag for oxfmt, allowing users to initialize a default configuration file (.oxfmtrc.jsonc) in their project. The implementation follows a similar pattern to oxlint's --init functionality, including automatic detection and inclusion of JSON schema references when available.

Key Changes

  • Added --init command-line flag that creates .oxfmtrc.jsonc with default configuration
  • New ConfigFileInitSucceeded and ConfigFileInitFailed result variants to handle initialization outcomes
  • Automatic $schema reference injection when node_modules/oxfmt/configuration_schema.json exists

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

File Description
apps/oxfmt/src/cli/command.rs Adds the init boolean flag to BasicOptions struct with hide_usage attribute
apps/oxfmt/src/cli/result.rs Adds two new enum variants for config initialization success/failure states and maps them to appropriate exit codes
apps/oxfmt/src/cli/format.rs Implements handle_init method to create default config file, includes early exit logic in run method, and adds comprehensive tests for both schema and non-schema scenarios

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

let config_path = cwd.join(Self::DEFAULT_OXFMTRC);
match fs::write(&config_path, configuration) {
Ok(()) => {
let _ = writeln!(stdout, "Configuration file created");
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The success message should include the filename that was created for better user feedback. For example: "Configuration file created at .oxfmtrc.jsonc". This is consistent with oxlint's implementation and provides clearer information to the user.

Suggested change
let _ = writeln!(stdout, "Configuration file created");
let _ = writeln!(stdout, "Configuration file created at {}", config_path.display());

Copilot uses AI. Check for mistakes.
Comment on lines +384 to +406
#[test]
fn test_init_config() {
let temp_dir = env::temp_dir().join("oxfmt_init_test");
fs::create_dir_all(&temp_dir).unwrap();

let config_path = temp_dir.join(FormatRunner::DEFAULT_OXFMTRC);
let _ = fs::remove_file(&config_path);

let mut stdout = Vec::new();
let mut stderr = Vec::new();
let result = FormatRunner::handle_init(&temp_dir, &mut stdout, &mut stderr);

assert!(matches!(result, CliRunResult::ConfigFileInitSucceeded));
assert!(config_path.exists());

// Verify valid JSON
let content = fs::read_to_string(&config_path).unwrap();
let _: serde_json::Value = serde_json::from_str(&content).unwrap();

// Cleanup
fs::remove_file(&config_path).unwrap();
fs::remove_dir(&temp_dir).unwrap();
}
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

Missing test coverage for the case when a configuration file already exists. Consider adding a test that verifies the behavior when --init is run and .oxfmtrc.jsonc already exists (e.g., whether it overwrites, fails, or prompts).

Copilot uses AI. Check for mistakes.
Comment on lines +22 to 25
Self::InvalidOptionConfig | Self::FormatMismatch | Self::ConfigFileInitFailed => {
ExitCode::from(1)
}
Self::NoFilesFound | Self::FormatFailed => ExitCode::from(2),
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

ConfigFileInitFailed is categorized under "Fatal error" in the comment but returns exit code 1 (warning error) in the implementation. This is inconsistent. If it's truly a fatal error, it should return exit code 2 like other fatal errors (NoFilesFound, FormatFailed). Otherwise, the comment should categorize it as a warning error.

Suggested change
Self::InvalidOptionConfig | Self::FormatMismatch | Self::ConfigFileInitFailed => {
ExitCode::from(1)
}
Self::NoFilesFound | Self::FormatFailed => ExitCode::from(2),
Self::InvalidOptionConfig | Self::FormatMismatch => {
ExitCode::from(1)
}
Self::NoFilesFound | Self::FormatFailed | Self::ConfigFileInitFailed => ExitCode::from(2),

Copilot uses AI. Check for mistakes.
config_string
};

// Write to .oxfmtrc.json
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The comment says "Write to .oxfmtrc.json" but the actual filename constant is .oxfmtrc.jsonc (with 'c' suffix). The comment should be updated to match the actual filename being used.

Suggested change
// Write to .oxfmtrc.json
// Write to .oxfmtrc.jsonc

Copilot uses AI. Check for mistakes.
Comment on lines +285 to +296
// Write to .oxfmtrc.json
let config_path = cwd.join(Self::DEFAULT_OXFMTRC);
match fs::write(&config_path, configuration) {
Ok(()) => {
let _ = writeln!(stdout, "Configuration file created");
CliRunResult::ConfigFileInitSucceeded
}
Err(e) => {
let _ = writeln!(stderr, "Failed to create configuration file: {e}");
CliRunResult::ConfigFileInitFailed
}
}
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The --init flag should check if the configuration file already exists before writing to prevent silently overwriting existing user configurations. Consider warning the user or failing gracefully if the file exists. Compare with common tools like npm init which prompts for confirmation or uses a --force flag for overwriting.

Copilot uses AI. Check for mistakes.
Comment on lines +272 to +280
let mut config_json: Value = serde_json::from_str(&config_string).unwrap();
if let Value::Object(ref mut obj) = config_json {
let mut json_object = serde_json::Map::new();
json_object
.insert("$schema".to_string(), format!("./{schema_relative_path}").into());
json_object.extend(obj.clone());
*obj = json_object;
}
serde_json::to_string_pretty(&config_json).unwrap()
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The .unwrap() calls on lines 272 and 280 could panic if JSON serialization/deserialization fails unexpectedly. While unlikely since we just successfully serialized the config, it's safer to handle these errors explicitly and return CliRunResult::ConfigFileInitFailed with an appropriate error message to stderr.

Copilot uses AI. Check for mistakes.
Comment on lines +285 to +296
// Write to .oxfmtrc.json
let config_path = cwd.join(Self::DEFAULT_OXFMTRC);
match fs::write(&config_path, configuration) {
Ok(()) => {
let _ = writeln!(stdout, "Configuration file created");
CliRunResult::ConfigFileInitSucceeded
}
Err(e) => {
let _ = writeln!(stderr, "Failed to create configuration file: {e}");
CliRunResult::ConfigFileInitFailed
}
}
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.

The code does not check if the configuration file already exists before writing to it. This will silently overwrite any existing .oxfmtrc.jsonc file, potentially causing data loss for users who already have a configuration.

// Check if config file already exists
let config_path = cwd.join(Self::DEFAULT_OXFMTRC);
if config_path.exists() {
    let _ = writeln!(stderr, "Configuration file already exists at {}", config_path.display());
    return CliRunResult::ConfigFileInitFailed;
}

match fs::write(&config_path, configuration) {
    // ...
}
Suggested change
// Write to .oxfmtrc.json
let config_path = cwd.join(Self::DEFAULT_OXFMTRC);
match fs::write(&config_path, configuration) {
Ok(()) => {
let _ = writeln!(stdout, "Configuration file created");
CliRunResult::ConfigFileInitSucceeded
}
Err(e) => {
let _ = writeln!(stderr, "Failed to create configuration file: {e}");
CliRunResult::ConfigFileInitFailed
}
}
// Write to .oxfmtrc.json
let config_path = cwd.join(Self::DEFAULT_OXFMTRC);
// Check if config file already exists
if config_path.exists() {
let _ = writeln!(stderr, "Configuration file already exists at {}", config_path.display());
return CliRunResult::ConfigFileInitFailed;
}
match fs::write(&config_path, configuration) {
Ok(()) => {
let _ = writeln!(stdout, "Configuration file created");
CliRunResult::ConfigFileInitSucceeded
}
Err(e) => {
let _ = writeln!(stderr, "Failed to create configuration file: {e}");
CliRunResult::ConfigFileInitFailed
}
}

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@leaysgur
Copy link
Copy Markdown
Member

The TODO has been finalized #16622, so I'll close this PR and redo it.

@leaysgur leaysgur closed this Dec 11, 2025
@leaysgur leaysgur deleted the 12-10-feat_oxfmt_oxfmt_--init_ branch December 11, 2025 01:07
graphite-app bot pushed a commit that referenced this pull request Dec 11, 2025
Follow up #16703, fixes #16622

I will add test for `--init` and also `--lsp` later.
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 C-enhancement Category - New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

oxfmt: oxfmt --init

3 participants