Skip to content

Commit 61def22

Browse files
committed
feat(fmt): prototype SWC Next 0.2.0 crate integration
1 parent 0e95ea8 commit 61def22

21 files changed

Lines changed: 510 additions & 228 deletions

Cargo.lock

Lines changed: 171 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ napi-build = "2.4.1"
1414
napi-derive = "3.6.3"
1515
pathdiff = "0.2.3"
1616
rstack-ignore = { path = "crates/rstack-ignore" }
17+
# The wire format must match @swc-next/decoder exactly.
18+
swc_next_bridge = { version = "=0.2.0", features = ["parser"] }
1719

1820
# Local development: 16 codegen units are sufficient for this small workspace while preserving
1921
# parallel compilation and full debugging support.

crates/rstack-binding/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ test = false
1414
napi.workspace = true
1515
napi-derive.workspace = true
1616
rstack-ignore.workspace = true
17+
swc_next_bridge.workspace = true
1718

1819
[build-dependencies]
1920
napi-build.workspace = true

crates/rstack-binding/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
#![deny(clippy::all)]
22

3+
mod parser;
4+
5+
pub use parser::parse_swc_next;
6+
37
use std::path::Path;
48

59
use napi::{bindgen_prelude::Uint8Array, Error, Status};
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use napi::{bindgen_prelude::Buffer, Error, Status};
2+
use napi_derive::napi;
3+
use swc_next_bridge::{parse_to_buffer, CommentMode, Lang, ParserOptions, SourceType};
4+
5+
/// Returns the SWC Next 0.2.0 wire format consumed by @swc-next/decoder.
6+
/// Keep parsing and serialization in the upstream crate, not in the NAPI adapter.
7+
#[napi]
8+
pub fn parse_swc_next(source: String, lang: String, source_type: String) -> napi::Result<Buffer> {
9+
let lang = match lang.as_str() {
10+
"js" => Lang::Js,
11+
"jsx" => Lang::Jsx,
12+
"ts" => Lang::Ts,
13+
"tsx" => Lang::Tsx,
14+
"dts" => Lang::Dts,
15+
_ => {
16+
return Err(Error::new(
17+
Status::InvalidArg,
18+
"Unsupported SWC Next language.",
19+
))
20+
}
21+
};
22+
let source_type = match source_type.as_str() {
23+
"module" => SourceType::Module,
24+
"commonjs" => SourceType::CommonJs,
25+
_ => {
26+
return Err(Error::new(
27+
Status::InvalidArg,
28+
"Unsupported SWC Next source type.",
29+
))
30+
}
31+
};
32+
33+
Ok(parse_to_buffer(
34+
&source,
35+
Some(ParserOptions {
36+
lang: Some(lang),
37+
source_type: Some(source_type),
38+
preserve_parens: Some(true),
39+
comments: Some(CommentMode::Flat),
40+
}),
41+
)
42+
.into())
43+
}

packages/rstack/SWC_NEXT_POC.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# SWC next formatter PoC
2+
3+
This branch replaces the default Yuku parser in `rs fmt` with SWC Next 0.2.0 while retaining Prettier's ESTree printer and the existing formatting adapter.
4+
5+
`swc_next_bridge = "=0.2.0"` compiles parsing and serialization into the existing rstack native binding. A thin NAPI function returns a Buffer to `@swc-next/decoder@0.2.0`; the generated loader is resolved lazily when parsing starts. No parser npm package or separate SWC Next native binary is installed.
6+
7+
Inferred JavaScript, JSX, TypeScript, TSX, and embedded script formatting use SWC Next. Explicit `babel` and `typescript` options still select Prettier's own parsers, and project plugins retain precedence. The experimental explicit parser names are `swc-next` and `swc-next-ts`, replacing `yuku` and `yuku-ts`.
8+
9+
The cache namespace includes the parser version and integration route so switching between the original formatter and either PoC cannot reuse stale formatting results. The decoder and Rust serializer must be upgraded together; all SWC Next packages in this PoC are locked to 0.2.0.
10+
11+
## Try it
12+
13+
```sh
14+
pnpm install
15+
pnpm build
16+
pnpm --filter rstack build:native
17+
printf 'const view=<Component value={{foo:1}} />' | pnpm exec rs fmt --stdin-filepath example.tsx
18+
pnpm test
19+
pnpm check
20+
```
21+
22+
Native changes also require `cargo fmt --all -- --check`, `cargo clippy --workspace --all-targets --locked -- -D warnings`, and `cargo test --workspace --locked`.
23+
24+
## Compatibility and limits
25+
26+
SWC Next 0.2.0 accepts function implementations in declaration files, for example `export function value() { return 1; }` in `example.d.ts`. Yuku previously rejected this with an ambient-context diagnostic. The tests explicitly record this upstream difference; valid declarations, comments, Unicode locations, JSX/TSX, CommonJS, pragmas, and syntax errors remain covered. No fallback to another parser hides SWC Next errors.
27+
28+
Validation is on macOS arm64 with the repository's Node.js, pnpm, and Rust versions. The complete formatter/CLI suite covers worker execution, stdin, LSP, Vue, Svelte, and caching. Cross-platform binaries and formatter-wide conformance against Prettier's upstream corpus have not been validated. No throughput advantage is claimed by this PoC.
29+
30+
## Upstream
31+
32+
[SWC Next 0.2.0 source](https://github.com/swc-project/swc-next/tree/v0.2.0)

packages/rstack/THIRD_PARTY_NOTICES.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2929
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3030
SOFTWARE.
3131

32-
## Prettier yuku parser adapter
32+
## Prettier SWC next parser adapter
3333

34-
The local Yuku parser adapter includes portions derived from
34+
The local SWC Next parser adapter includes portions derived from
3535
[@prettier/plugin-yuku](https://github.com/prettier/prettier/tree/main/packages/plugin-yuku)
3636
and Prettier's JavaScript parser postprocessing. The adapter reuses the public
3737
ESTree printer, formatter options, and parser utilities from the installed

packages/rstack/binding.cjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,3 +702,7 @@ if (!nativeBinding) {
702702
module.exports = nativeBinding
703703
module.exports.GitIgnoreMatcher = nativeBinding.GitIgnoreMatcher
704704
module.exports.IgnoreMatcher = nativeBinding.IgnoreMatcher
705+
module.exports.parseSwcNext = nativeBinding.parseSwcNext
706+
module.exports.CommentMode = nativeBinding.CommentMode
707+
module.exports.Lang = nativeBinding.Lang
708+
module.exports.SourceType = nativeBinding.SourceType

0 commit comments

Comments
 (0)