1- import type { Options } from "prettier" ;
1+ import Tinypool from "tinypool" ;
2+ import type { WorkerData , FormatEmbeddedCodeArgs , FormatFileArgs } from "./prettier-worker.ts" ;
23
3- // Import Prettier lazily.
4- // This helps to reduce initial load time if not needed.
5- //
6- // Also, this solves unknown issue described below...
7- //
8- // XXX: If import `prettier` directly here, it will add line like this to the output JS:
9- // ```js
10- // import process2 from 'process';
11- // ```
12- // Yes, this seems completely fine!
13- // But actually, this makes `oxfmt --lsp` immediately stop with `Parse error` JSON-RPC error
14- let prettierCache : typeof import ( "prettier" ) ;
15-
16- // Cache for Prettier options.
17- // Set by `setupConfig` function once.
18- //
19- // Read `.oxfmtrc.json(c)` directly does not work,
20- // because our brand new defaults are not compatible with Prettier's defaults.
21- // So we need to pass the config from Rust side after merging with our defaults.
22- let configCache : Options = { } ;
4+ // Worker pool for parallel Prettier formatting
5+ let pool : Tinypool | null = null ;
236
247// ---
258
269/**
2710 * Setup Prettier configuration.
2811 * NOTE: Called from Rust via NAPI ThreadsafeFunction with FnArgs
2912 * @param configJSON - Prettier configuration as JSON string
13+ * @param numThreads - Number of worker threads to use (same as Rayon thread count)
3014 * @returns Array of loaded plugin's `languages` info
3115 * */
32- export async function setupConfig ( configJSON : string ) : Promise < string [ ] > {
33- // NOTE: `napi-rs` has ability to pass `Object` directly.
34- // But since we don't know what options various plugins may specify,
35- // we have to receive it as a JSON string and parse it.
36- //
37- // SAFETY: This is valid JSON string generated in Rust side
38- configCache = JSON . parse ( configJSON ) as Options ;
16+ export async function setupConfig ( configJSON : string , numThreads : number ) : Promise < string [ ] > {
17+ const workerData : WorkerData = {
18+ // SAFETY: Always valid JSON constructed by Rust side
19+ prettierConfig : JSON . parse ( configJSON ) ,
20+ } ;
21+
22+ if ( pool ) throw new Error ( "`setupConfig()` has already been called" ) ;
23+
24+ // Initialize worker pool for parallel Prettier formatting
25+ // Pass config via workerData so all workers get it on initialization
26+ pool = new Tinypool ( {
27+ filename : new URL ( "./prettier-worker.js" , import . meta. url ) . href ,
28+ minThreads : numThreads ,
29+ maxThreads : numThreads ,
30+ workerData,
31+ } ) ;
3932
4033 // TODO: Plugins support
4134 // - Read `plugins` field
@@ -51,14 +44,11 @@ const TAG_TO_PARSER: Record<string, string> = {
5144 // CSS
5245 css : "css" ,
5346 styled : "css" ,
54-
5547 // GraphQL
5648 gql : "graphql" ,
5749 graphql : "graphql" ,
58-
5950 // HTML
6051 html : "html" ,
61-
6252 // Markdown
6353 md : "markdown" ,
6454 markdown : "markdown" ,
@@ -74,22 +64,14 @@ const TAG_TO_PARSER: Record<string, string> = {
7464export async function formatEmbeddedCode ( tagName : string , code : string ) : Promise < string > {
7565 const parser = TAG_TO_PARSER [ tagName ] ;
7666
67+ // Unknown tag, return original code
7768 if ( ! parser ) {
78- // Unknown tag, return original code
7969 return code ;
8070 }
8171
82- if ( ! prettierCache ) {
83- prettierCache = await import ( "prettier" ) ;
84- }
85-
86- return prettierCache
87- . format ( code , {
88- ...configCache ,
89- parser,
90- } )
91- . then ( ( formatted ) => formatted . trimEnd ( ) )
92- . catch ( ( ) => code ) ;
72+ return pool ! . run ( { parser, code } satisfies FormatEmbeddedCodeArgs , {
73+ name : "formatEmbeddedCode" ,
74+ } ) ;
9375}
9476
9577// ---
@@ -107,13 +89,7 @@ export async function formatFile(
10789 fileName : string ,
10890 code : string ,
10991) : Promise < string > {
110- if ( ! prettierCache ) {
111- prettierCache = await import ( "prettier" ) ;
112- }
113-
114- return prettierCache . format ( code , {
115- ...configCache ,
116- parser : parserName ,
117- filepath : fileName ,
92+ return pool ! . run ( { parserName, fileName, code } satisfies FormatFileArgs , {
93+ name : "formatFile" ,
11894 } ) ;
11995}
0 commit comments