Skip to content

feat(oxfmt): Expose Node.js API: format(fileName, sourceText, options?)#16939

Merged
graphite-app[bot] merged 1 commit intomainfrom
12-16-feat_oxfmt_expose_node.js_api_format_
Dec 16, 2025
Merged

feat(oxfmt): Expose Node.js API: format(fileName, sourceText, options?)#16939
graphite-app[bot] merged 1 commit intomainfrom
12-16-feat_oxfmt_expose_node.js_api_format_

Conversation

@leaysgur
Copy link
Member

@leaysgur leaysgur commented Dec 16, 2025

Fixes #15913

@leaysgur leaysgur requested a review from Dunqing as a code owner December 16, 2025 05:47
@github-actions github-actions bot added A-cli Area - CLI A-formatter Area - Formatter C-enhancement Category - New feature or request labels Dec 16, 2025
@leaysgur leaysgur changed the title feat(oxfmt): Expose Node.js API: format\(\) feat(oxfmt): Expose Node.js API: format(fileName, sourceText, options?) Dec 16, 2025
Copy link
Member Author

leaysgur commented Dec 16, 2025


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • 0-merge - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@codspeed-hq
Copy link

codspeed-hq bot commented Dec 16, 2025

CodSpeed Performance Report

Merging #16939 will not alter performance

Comparing 12-16-feat_oxfmt_expose_node.js_api_format_ (3eac019) with main (fc96ee0)1

Summary

✅ 42 untouched
⏩ 3 skipped2

Footnotes

  1. No successful run was found on main (be9fb35) during the generation of this report, so fc96ee0 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

  2. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@leaysgur leaysgur marked this pull request as draft December 16, 2025 06:20
@leaysgur leaysgur force-pushed the 12-16-feat_oxfmt_expose_node.js_api_format_ branch from e495e7b to ad5e335 Compare December 16, 2025 06:31
@leaysgur leaysgur force-pushed the 12-16-test_oxfmt_test_ignorepatterns_is_inserted_at_the_bottom branch from 0e95ef6 to d830984 Compare December 16, 2025 06:46
@leaysgur leaysgur force-pushed the 12-16-feat_oxfmt_expose_node.js_api_format_ branch from ed6e483 to 16f0755 Compare December 16, 2025 06:46
@leaysgur leaysgur marked this pull request as ready for review December 16, 2025 06:49
Copy link
Member

@Dunqing Dunqing left a comment

Choose a reason for hiding this comment

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

I noticed that the current format API is directly delegated to the Rust side's format. I think we should change it to be used only when necessary; otherwise, we should delegate to formatFile on the JS side, which can avoid calling setupConfig on the Rust side, as it already owns the configuration. This way, #16934 is no longer needed.

@leaysgur
Copy link
Member Author

@Dunqing As the current design, these are intentional.

Can we set up the config on the JS side?

To handle this entirely on the JS side, validation and applying default values would have to be done in JS.

However, if printWidth is absent in the options, Rust logic is required to determine that it should be 100.

https://github.com/oxc-project/oxc/blob/main/apps/oxfmt/src/core/config.rs#L37

Incidentally, the upcoming implementation for editorconfig will make this approach of caching settings on the first run impossible anyway (since it varies per path...), so coincidentally, it will be resolved.

Can we determine if the file should delegate to Prettier on the JS side?

Similarly, the logic to determine whether to call Prettier based on the filename exists only on the Rust side.

https://github.com/oxc-project/oxc/blob/main/apps/oxfmt/src/core/support.rs


Ultimately, it might be possible to make all necessary parts publicly available via napi and usable on the JS side, but I think a slightly later timing would be better.

@leaysgur leaysgur requested a review from Dunqing December 16, 2025 09:37
@graphite-app graphite-app bot changed the base branch from 12-16-test_oxfmt_test_ignorepatterns_is_inserted_at_the_bottom to graphite-base/16939 December 16, 2025 11:41
@graphite-app graphite-app bot force-pushed the graphite-base/16939 branch from d830984 to 71ee6e8 Compare December 16, 2025 11:48
@graphite-app graphite-app bot force-pushed the 12-16-feat_oxfmt_expose_node.js_api_format_ branch from 16f0755 to 4b54344 Compare December 16, 2025 11:48
@graphite-app graphite-app bot changed the base branch from graphite-base/16939 to main December 16, 2025 11:49
@graphite-app graphite-app bot force-pushed the 12-16-feat_oxfmt_expose_node.js_api_format_ branch from 4b54344 to 5335580 Compare December 16, 2025 11:49
@graphite-app graphite-app bot changed the base branch from main to graphite-base/16939 December 16, 2025 12:31
@graphite-app graphite-app bot force-pushed the 12-16-feat_oxfmt_expose_node.js_api_format_ branch from 5335580 to d8be01f Compare December 16, 2025 12:37
@graphite-app graphite-app bot changed the base branch from graphite-base/16939 to main December 16, 2025 12:37
@graphite-app graphite-app bot force-pushed the 12-16-feat_oxfmt_expose_node.js_api_format_ branch from d8be01f to 3eac019 Compare December 16, 2025 12:38
@Dunqing
Copy link
Member

Dunqing commented Dec 16, 2025

To handle this entirely on the JS side, validation and applying default values would have to be done in JS.

However, if printWidth is absent in the options, Rust logic is required to determine that it should be 100.

https://github.com/oxc-project/oxc/blob/main/apps/oxfmt/src/core/config.rs#L37

I think this is fine if you pass { printWidth: 100, ...userOptions } to Prettier

Incidentally, the upcoming implementation for editorconfig will make this approach of caching settings on the first run impossible anyway (since it varies per path...), so coincidentally, it will be resolved.

I might remember incorrectly; didn't Boshen say that we only support root-level editorconfig?

Similarly, the logic to determine whether to call Prettier based on the filename exists only on the Rust side.

https://github.com/oxc-project/oxc/blob/main/apps/oxfmt/src/core/support.rs

I know that, but on the JS side, shouldn't we only need to check which files can be formatted by the Rust side? That would be much simpler than checking for an external formatter

Ultimately, it might be possible to make all necessary parts publicly available via napi and usable on the JS side, but I think a slightly later timing would be better.

Anyway, I am not keen to get this change immediately, just brought this up to see what we can improve here. So let's get this merge and iterate on it.

@Dunqing Dunqing added the 0-merge Merge with Graphite Merge Queue label Dec 16, 2025
Copy link
Member

Dunqing commented Dec 16, 2025

Merge activity

Copilot AI review requested due to automatic review settings December 16, 2025 13:43
@graphite-app graphite-app bot force-pushed the 12-16-feat_oxfmt_expose_node.js_api_format_ branch from 3eac019 to 8c33ff4 Compare December 16, 2025 13:43
Copy link
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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@graphite-app graphite-app bot merged commit 8c33ff4 into main Dec 16, 2025
21 checks passed
@graphite-app graphite-app bot deleted the 12-16-feat_oxfmt_expose_node.js_api_format_ branch December 16, 2025 13:49
@graphite-app graphite-app bot removed the 0-merge Merge with Graphite Merge Queue label Dec 16, 2025
@leaysgur
Copy link
Member Author

Thank you. I think your point is still valid.

I also just realized that worker_threads isn't necessary for API usage, so I'll improve it later. 👍🏻

@leaysgur leaysgur mentioned this pull request Dec 17, 2025
overlookmotel added a commit that referenced this pull request Dec 19, 2025
# Oxlint
### 🚀 Features

- 6cc3fdf linter/no-inferrable-types: Implement fixer (#17090) (camc314)
- 2067997 linter/no-negation-in-equality-check: Implement suggestion
(#17084) (camc314)
- 552f9ef vscode: Auto-generate VSCode README configuration from
package.json (#16970) (Copilot)
- 9190c4b linter/no-unnecessary-array-flat-depth: Implement fixer
(#17057) (camc314)
- ed789de linter/misrefactored-assign-op: Implement fixer (#17056)
(camc314)
- a0f74a0 linter/config: Allow aliasing plugin names to allow names the
same as builtin plugins (#15569) (Cameron)
- a43d251 linter/plugins: `RuleTester` support `languageOptions.globals`
(#17009) (overlookmotel)
- 35070d9 linter/bad-bitwise-operator: Implement fixer (#17006)
(camc314)
- 322d995 linter/prefer-enum-initializers: Implement fixer (#17004)
(camc314)
- ae1e5bc vscode: Add support for tsgolint binary configuration (#16921)
(ColemanDunn)
- 3bfe31e linter/eslint-plugin-vitest: Add prefer-called-with as vitest
compatible jest rule (#16993) (Said Atrahouch)
- 0cd075f linter/eslint-plugin-jest: Add fix capabilities to
prefer-called-with rule (#16987) (Said Atrahouch)
- 357564b linter: Add options for
`typescript/require-array-sort-compare` rule. (#16980) (connorshea)
- 2b0ffba linter: Add options for
`typescript/no-meaningless-void-operator` rule. (#16981) (connorshea)
- 8bc4287 linter/plugins: Validate options against schema (#16974)
(overlookmotel)
- fdc7d08 linter: Implement eslint/capitalized-comments (#16896) (Tu
Shaokun)
- f8b6561 linter: Add support for `test.for` in vitest (#16925)
(camchenry)
- 7ee0379 linter/eslint-plugin-vitest: Implement prefer-spy-on (#16426)
(Said Atrahouch)
- fc96ee0 linter: Implement jest/prefer-to-have-been-called-times
(#16938) (秦宇航)
- 291b57b ast_tools: Generate TS declaration files for deserializer and
walk files (#16912) (camc314)
- e31da2a linter: Implement jest/perfer-to-have-been-called (#16899)
(秦宇航)
- 1a31306 linter/eslint-plugin-vitest: Add require-hook as vitest
compatible jest rule (#16880) (Said Atrahouch)
- cd3db21 linter: Add ignoredTypeNames option to no-base-to-string rule
(#16898) (camc314)
- 763b25a linter: Implement eslint/no-inline-comments (#16885) (Tu
Shaokun)

### 🐛 Bug Fixes

- fb9e193 linter: OOM problems with custom plugins (#17082)
(overlookmotel)
- 005ec25 linter: Permit `$schema` `.oxlintrc.json` struct (#17060)
(Copilot)
- fd03131 linter/plugins: Handle plugin names containing slashes
(#17073) (overlookmotel)
- b2a4fac linter/plugins: Error if plugin name alias is not normalized
(#17071) (overlookmotel)
- e046c4e linter/no-misused-spread: Add rule options support (#17054)
(camc314)
- 5c1a9e0 linter/no-deprecated: Add rule options support (#17053)
(camc314)
- 8c9cafe linter: `import/consistent-type-specifier-style`: add support
for declaration files (#16979) (camchenry)
- dab4780 linter/no-empty-pattern: Misleading help message for arrays
(#17039) (Copilot)
- 67f8c5d linter/plugins: Get correct plugin name in all cases (#17033)
(overlookmotel)
- 674dab9 linter/plugins: Fix indentation in error message (#17018)
(overlookmotel)
- 6524f72 linter/plugins: Add `@types/node` dev dependency to `oxlint`
package (#17016) (overlookmotel)
- 7a35513 linter/plugins: Better error for `null` in `globals` in
`RuleTester` (#17011) (overlookmotel)
- 42603ba linter/plugins: Always define `languageOptions.globals`
(#17008) (overlookmotel)
- 4cdc2f8 linter: Fix VITEST override rule list and add test for
alphabetizing the two lists (#16975) (Connor Shea)
- e466562 linter/consistent-type-definitions: Handle parenthesized types
in rule (#16998) (camc314)
- fce267c linter: Correct vitest plugin source to be
`@vitest/eslint-plugin` (#16976) (connorshea)
- 477bb57 linter: Fix `vitest/no-restricted-vi-methods` and add tests
for it. (#16971) (connorshea)
- 7d6974d linter: Ignore oxlint directive comments in
capitalized-comments (#16989) (Tu Shaokun)
- 23ac6b1 linter/plugins: Apply defaults from `meta.schema` to options
(#16930) (overlookmotel)
- 2f946cf linter/plugins: Error if `defaultOptions` is not
JSON-serializable (#16959) (overlookmotel)
- d8b8a57 linter/plugins: Freeze whole of merged options (#16958)
(overlookmotel)
- d446c43 linter: Prevent extra fields from being present on oxlint
config file (#16874) (connorshea)
- b845871 linter/plugins: Correctly handle object with `__proto__` keys
in options merging (#16928) (overlookmotel)
- c897794 linter: Fix eslint/sort-imports allowSeparatedGroups not
working with single empty line (#16012) (Duc Nghiem Xuan)
- 0c347a1 linter/array-type: Handle satisfies expression (#16903)
(camc314)

### ⚡ Performance

- 70d853c linter: Avoid cloning source text when cloning AST into
fixed-size allocator (#17088) (overlookmotel)
- 4d389f7 linter: Less bounds checks in `normalize_plugin_name` (#17030)
(overlookmotel)
- fd8e9c6 linter/plugins: Speed up cloning JSON objects (#16997)
(overlookmotel)
- d77e22d linter/plugins: Use `DEFAULT_OPTIONS` for rules with empty
array as default options (#16913) (overlookmotel)

### 📚 Documentation

- 6d053b4 linter: Fix typo in doc comment (#17091) (overlookmotel)
- b5f3c91 linter: Document intentional exclusion of ignoreCase option in
jsx-no-duplicate-props (#17046) (Copilot)
- a0bf5d8 linter: Fix the config option docs for no-inline-comments
rule. (#16983) (connorshea)
- ca26a11 linter/plugins: Fix typo in doc comment (#16966)
(overlookmotel)
- 3183bf8 linter/plugins: Fix typo in JSDoc comment (#16900)
(overlookmotel)
# Oxfmt
### 🚀 Features

- 15dfb55 oxfmt: Respect single nearest `.editorconfig` (#17043)
(leaysgur)
- 8c33ff4 oxfmt: Expose Node.js API: `format(fileName, sourceText,
options?)` (#16939) (leaysgur)

### 🐛 Bug Fixes

- d340c87 oxfmt: Update api `FormatOptions` type with `& Record<string,
unknown>` (#17036) (leaysgur)
- 827a256 oxfmt: Place ignorePatterns at bottom of JSON in --migrate
prettier (#16926) (Boshen)

Co-authored-by: overlookmotel <[email protected]>
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: node API

2 participants

Comments