diff --git a/crates/rome_service/src/file_handlers/json.rs b/crates/rome_service/src/file_handlers/json.rs index b6eb63a7754..3bb03029997 100644 --- a/crates/rome_service/src/file_handlers/json.rs +++ b/crates/rome_service/src/file_handlers/json.rs @@ -6,17 +6,15 @@ use crate::settings::{ }; use crate::workspace::GetSyntaxTreeResult; use crate::RomeError; -#[cfg(debug_assertions)] -use rome_formatter::FormatError; -use rome_formatter::Printed; +#[cfg(any(debug_assertions, target_family = "wasm"))] +use rome_formatter::{FormatError, Printed}; use rome_fs::RomePath; use rome_json_formatter::context::JsonFormatOptions; use rome_json_formatter::format_node; use rome_json_syntax::{JsonLanguage, JsonRoot, JsonSyntaxNode}; use rome_parser::AnyParse; -#[cfg(debug_assertions)] +#[cfg(any(debug_assertions, target_family = "wasm"))] use rome_rowan::{TextRange, TextSize, TokenAtOffset}; -use tracing::debug; impl Language for JsonLanguage { type FormatterSettings = (); @@ -68,7 +66,7 @@ impl ExtensionHandler for JsonFileHandler { } } -#[cfg(debug_assertions)] +#[cfg(any(debug_assertions, target_family = "wasm"))] fn formatter_capabilities() -> FormatterCapabilities { FormatterCapabilities { format: Some(format), @@ -77,7 +75,7 @@ fn formatter_capabilities() -> FormatterCapabilities { } } -#[cfg(not(debug_assertions))] +#[cfg(all(not(debug_assertions), not(target_family = "wasm")))] fn formatter_capabilities() -> FormatterCapabilities { FormatterCapabilities::default() } @@ -112,6 +110,7 @@ fn debug_formatter_ir( Ok(root_element.to_string()) } +#[cfg(any(debug_assertions, target_family = "wasm"))] #[tracing::instrument(level = "debug", skip(parse))] fn format( rome_path: &RomePath, @@ -120,7 +119,7 @@ fn format( ) -> Result { let options = settings.format_options::(rome_path); - debug!("Format with the following options: \n{}", options); + tracing::debug!("Format with the following options: \n{}", options); let tree = parse.syntax(); let formatted = format_node(options, &tree)?; @@ -131,7 +130,7 @@ fn format( } } -#[cfg(debug_assertions)] +#[cfg(any(debug_assertions, target_family = "wasm"))] fn format_range( rome_path: &RomePath, parse: AnyParse, @@ -145,7 +144,7 @@ fn format_range( Ok(printed) } -#[cfg(debug_assertions)] +#[cfg(any(debug_assertions, target_family = "wasm"))] fn format_on_type( rome_path: &RomePath, parse: AnyParse, diff --git a/website/package.json b/website/package.json index 47b2b436dd9..e0beddf5148 100644 --- a/website/package.json +++ b/website/package.json @@ -18,6 +18,7 @@ "@astrojs/react": "^1.2.2", "@astrojs/rss": "^1.0.3", "@codemirror/lang-javascript": "^6.1.0", + "@codemirror/lang-json": "^6.0.1", "@codemirror/lint": "^6.0.0", "@codemirror/state": "6.1.2", "@codemirror/view": "6.4.0", diff --git a/website/pnpm-lock.yaml b/website/pnpm-lock.yaml index fbce16473a9..00cf9c6dd03 100644 --- a/website/pnpm-lock.yaml +++ b/website/pnpm-lock.yaml @@ -6,6 +6,7 @@ specifiers: '@astrojs/react': ^1.2.2 '@astrojs/rss': ^1.0.3 '@codemirror/lang-javascript': ^6.1.0 + '@codemirror/lang-json': ^6.0.1 '@codemirror/lint': ^6.0.0 '@codemirror/state': 6.1.2 '@codemirror/view': 6.4.0 @@ -49,6 +50,7 @@ dependencies: '@astrojs/react': 1.2.2_74b3ggvk3akyhuq4eydyx3fqim '@astrojs/rss': 1.0.3 '@codemirror/lang-javascript': 6.1.1 + '@codemirror/lang-json': 6.0.1 '@codemirror/lint': 6.0.0 '@codemirror/state': 6.1.2 '@codemirror/view': 6.4.0 @@ -61,7 +63,7 @@ dependencies: '@types/prettier': 2.7.1 '@types/react': 17.0.52 '@types/react-dom': 17.0.18 - '@uiw/react-codemirror': 4.13.2_ai5dpkfsh6bew42tf7jao77pla + '@uiw/react-codemirror': 4.13.2_j2evrivwfzdgwlskrcnfwd23wi '@vitejs/plugin-react': 2.2.0_vite@3.1.8 astro: 1.6.7_ajklay5k626t46b6fyghkbup3i astro-compress: 1.1.3 @@ -623,11 +625,8 @@ packages: resolution: {integrity: sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg==} dev: false - /@codemirror/autocomplete/6.3.0_ebfztrivxsawr3nzgdquexqq6q: + /@codemirror/autocomplete/6.3.0: resolution: {integrity: sha512-4jEvh3AjJZTDKazd10J6ZsCIqaYxDMCeua5ouQxY8hlFIml+nr7le0SgBhT3SIytFBmdzPK3AUhXGuW3T79nVg==} - peerDependencies: - '@codemirror/state': ^6.0.0 - '@codemirror/view': ^6.0.0 dependencies: '@codemirror/language': 6.3.0 '@codemirror/state': 6.1.2 @@ -647,7 +646,7 @@ packages: /@codemirror/lang-javascript/6.1.1: resolution: {integrity: sha512-F4+kiuC5d5dUSJmff96tJQwpEXs/tX/4bapMRnZWW6bHKK1Fx6MunTzopkCUWRa9bF87GPmb9m7Qtg7Yv8f3uQ==} dependencies: - '@codemirror/autocomplete': 6.3.0_ebfztrivxsawr3nzgdquexqq6q + '@codemirror/autocomplete': 6.3.0 '@codemirror/language': 6.3.0 '@codemirror/lint': 6.0.0 '@codemirror/state': 6.1.2 @@ -656,6 +655,13 @@ packages: '@lezer/javascript': 1.0.2 dev: false + /@codemirror/lang-json/6.0.1: + resolution: {integrity: sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==} + dependencies: + '@codemirror/language': 6.3.0 + '@lezer/json': 1.0.0 + dev: false + /@codemirror/language/6.3.0: resolution: {integrity: sha512-6jOE5DEt6sKD46SXhn3xPbBehn+l48ACcA6Uxs2k+E2YNH9XGF5WdGMTYr2DlggfK4h0QZBK6zEb5S7lkTriWA==} dependencies: @@ -859,6 +865,13 @@ packages: '@lezer/lr': 1.2.4 dev: false + /@lezer/json/1.0.0: + resolution: {integrity: sha512-zbAuUY09RBzCoCA3lJ1+ypKw5WSNvLqGMtasdW6HvVOqZoCpPr8eWrsGnOVWGKGn8Rh21FnrKRVlJXrGAVUqRw==} + dependencies: + '@lezer/highlight': 1.1.2 + '@lezer/lr': 1.2.4 + dev: false + /@lezer/lr/1.2.4: resolution: {integrity: sha512-L/52/oMJBFXXx8qBYF4UgktLP2geQ/qn5Fd8+5L/mqlLLCB9+qdKktFAtejd9FdFMaFx6lrP5rmLz4sN3Kplcg==} dependencies: @@ -1312,14 +1325,10 @@ packages: resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} dev: false - /@uiw/codemirror-extensions-basic-setup/4.13.2_taect3vlcl4b4hfcnqjzfij36u: + /@uiw/codemirror-extensions-basic-setup/4.13.2: resolution: {integrity: sha512-ATJA7WaZ5g7/0teNBQRIalK3RxfU9X7hviwh6BOelaeJrJjkY6x+jVaACYywP1GStsIKcjNCumakpmRPO9w4sQ==} - peerDependencies: - '@codemirror/lint': '>=6.0.0' - '@codemirror/state': '>=6.0.0' - '@codemirror/view': '>=6.0.0' dependencies: - '@codemirror/autocomplete': 6.3.0_ebfztrivxsawr3nzgdquexqq6q + '@codemirror/autocomplete': 6.3.0 '@codemirror/commands': 6.1.2 '@codemirror/language': 6.3.0 '@codemirror/lint': 6.0.0 @@ -1328,10 +1337,9 @@ packages: '@codemirror/view': 6.4.0 dev: false - /@uiw/react-codemirror/4.13.2_ai5dpkfsh6bew42tf7jao77pla: + /@uiw/react-codemirror/4.13.2_j2evrivwfzdgwlskrcnfwd23wi: resolution: {integrity: sha512-sMfb8F82yLSqyq1gEUlr14E4KGXDfvsCnkGLLwJZqsq/TvJTRVcy0GX87wn3GXBtGhNp5TvGFUDaCnFzbU4bIQ==} peerDependencies: - '@codemirror/state': '>=6.0.0' '@codemirror/view': '>=6.0.0' react: '>=16.8.0' react-dom: '>=16.8.0' @@ -1341,12 +1349,10 @@ packages: '@codemirror/state': 6.1.2 '@codemirror/theme-one-dark': 6.1.0 '@codemirror/view': 6.4.0 - '@uiw/codemirror-extensions-basic-setup': 4.13.2_taect3vlcl4b4hfcnqjzfij36u + '@uiw/codemirror-extensions-basic-setup': 4.13.2 codemirror: 6.0.1 react: 17.0.2 react-dom: 17.0.2_react@17.0.2 - transitivePeerDependencies: - - '@codemirror/lint' dev: false /@vitejs/plugin-react/2.2.0_vite@3.1.8: @@ -1785,7 +1791,7 @@ packages: /codemirror-lang-rome-ast/0.0.6: resolution: {integrity: sha512-2E4E4rNcj6XxLsVjCZJeOsdEXpfdgiejuLrbq6O4muXzf0KSv5X0ScQrs3LK5LmGwoQUC0AowYbfdj3lsaLWkQ==} dependencies: - '@codemirror/autocomplete': 6.3.0_ebfztrivxsawr3nzgdquexqq6q + '@codemirror/autocomplete': 6.3.0 '@codemirror/language': 6.3.0 '@codemirror/state': 6.1.2 '@codemirror/view': 6.4.0 @@ -1797,7 +1803,7 @@ packages: /codemirror/6.0.1: resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} dependencies: - '@codemirror/autocomplete': 6.3.0_ebfztrivxsawr3nzgdquexqq6q + '@codemirror/autocomplete': 6.3.0 '@codemirror/commands': 6.1.2 '@codemirror/language': 6.3.0 '@codemirror/lint': 6.0.0 @@ -3780,7 +3786,7 @@ packages: /lang-rome-formatter-ir/0.0.2: resolution: {integrity: sha512-Zx7uZ6SA1vmMWkM7UbDZlex8MGOCQNBkxN9sAjeGgGHx69DNuR8E4GPfHFHI2P7oFLvXMrmAMPUY2jbEH9wtOA==} dependencies: - '@codemirror/autocomplete': 6.3.0_ebfztrivxsawr3nzgdquexqq6q + '@codemirror/autocomplete': 6.3.0 '@codemirror/language': 6.3.0 '@codemirror/state': 6.1.2 '@codemirror/view': 6.4.0 diff --git a/website/src/playground/Playground.tsx b/website/src/playground/Playground.tsx index b0df9315553..45c5fd9c876 100644 --- a/website/src/playground/Playground.tsx +++ b/website/src/playground/Playground.tsx @@ -4,6 +4,7 @@ import CodeMirror from "./CodeMirror"; import type { ViewUpdate } from "@codemirror/view"; import * as codeMirrorLangRomeAST from "codemirror-lang-rome-ast"; import { javascript } from "@codemirror/lang-javascript"; +import { json } from "@codemirror/lang-json"; import SettingsPane from "./components/SettingsPane"; import { createRef, @@ -21,6 +22,7 @@ import FormatterIRTab from "./tabs/FormatterIRTab"; import { getCurrentCode, getFileState, + isJSONFilename, isJSXFilename, isTypeScriptFilename, useWindowSize, @@ -46,18 +48,18 @@ export default function PlaygroundLoader({ const prettierOutput = file.prettier; // rome-ignore lint/nursery/useExhaustiveDependencies: dynamic dependencies - const codeMirrorExtensions = useMemo( - () => [ - javascript({ - jsx: isJSXFilename(playgroundState.currentFile), - typescript: isTypeScriptFilename(playgroundState.currentFile), - }), - ], - [ - isJSXFilename(playgroundState.currentFile), - isTypeScriptFilename(playgroundState.currentFile), - ], - ); + const codeMirrorExtensions = useMemo(() => { + if (isJSONFilename(playgroundState.currentFile)) { + return [json()]; + } else { + return [ + javascript({ + jsx: isJSXFilename(playgroundState.currentFile), + typescript: isTypeScriptFilename(playgroundState.currentFile), + }), + ]; + } + }, [playgroundState.currentFile]); const romeAstSyntacticDataRef = useRef(null); diff --git a/website/src/playground/utils.ts b/website/src/playground/utils.ts index 56d7c31c3cf..4e8703d7721 100644 --- a/website/src/playground/utils.ts +++ b/website/src/playground/utils.ts @@ -1,16 +1,7 @@ import { Dispatch, SetStateAction, useEffect, useState } from "react"; -import prettier, { Options as PrettierOptions } from "prettier"; import type { ThemeName } from "../frontend-scripts/util"; -// @ts-ignore -import parserBabel from "prettier/esm/parser-babel"; import { - IndentStyle, PlaygroundState, - QuoteStyle, - QuoteProperties, - TrailingComma, - Semicolons, - PrettierOutput, PlaygroundSettings, emptyPrettierOutput, emptyRomeOutput, @@ -147,76 +138,6 @@ export function createPlaygroundSettingsSetter< }; } -export function formatWithPrettier( - code: string, - options: { - lineWidth: number; - indentStyle: IndentStyle; - indentWidth: number; - language: "js" | "ts"; - quoteStyle: QuoteStyle; - quoteProperties: QuoteProperties; - trailingComma: TrailingComma; - semicolons: Semicolons; - }, -): PrettierOutput { - try { - const prettierOptions: PrettierOptions = { - useTabs: options.indentStyle === IndentStyle.Tab, - tabWidth: options.indentWidth, - printWidth: options.lineWidth, - parser: getPrettierParser(options.language), - plugins: [parserBabel], - singleQuote: options.quoteStyle === QuoteStyle.Single, - quoteProps: options.quoteProperties, - trailingComma: options.trailingComma, - semi: options.semicolons === Semicolons.Always, - }; - - // @ts-ignore - const debug = prettier.__debug; - const document = debug.printToDoc(code, prettierOptions); - - // formatDoc must be before printDocToString because printDocToString mutates the document and breaks the ir - const ir = debug.formatDoc(document, { - parser: "babel", - plugins: [parserBabel], - }); - - const formattedCode = debug.printDocToString( - document, - prettierOptions, - ).formatted; - - return { - type: "SUCCESS", - code: formattedCode, - ir, - }; - } catch (err: unknown) { - if (err instanceof SyntaxError) { - return { - type: "ERROR", - stack: err.message, - }; - } else { - return { - type: "ERROR", - stack: (err as Error).stack ?? "", - }; - } - } -} - -function getPrettierParser(language: "js" | "ts"): string { - switch (language) { - case "js": - return "babel"; - case "ts": - return "babel-ts"; - } -} - // See https://developer.mozilla.org/en-US/docs/Web/API/btoa#unicode_strings export function encodeCode(code: string): string { return btoa(toBinary(code)); @@ -300,6 +221,10 @@ export function isModuleFilename(filename: string): boolean { ); } +export function isJSONFilename(filename: string): boolean { + return filename.endsWith(".json"); +} + export function modifyFilename( filename: string, opts: ExtensionOptions, @@ -344,7 +269,8 @@ export function isValidExtension(filename: string): boolean { isScriptFilename(filename) || isModuleFilename(filename) || isTypeScriptFilename(filename) || - isJSXFilename(filename) + isJSXFilename(filename) || + isJSONFilename(filename) ); } diff --git a/website/src/playground/workers/prettierWorker.ts b/website/src/playground/workers/prettierWorker.ts index 2a2c3ab3efb..704b7ff0f83 100644 --- a/website/src/playground/workers/prettierWorker.ts +++ b/website/src/playground/workers/prettierWorker.ts @@ -1,5 +1,17 @@ -import { formatWithPrettier, isTypeScriptFilename } from "../utils"; -import { defaultPlaygroundState, PlaygroundSettings } from "../types"; +import { + IndentStyle, + PlaygroundSettings, + PrettierOutput, + QuoteProperties, + QuoteStyle, + Semicolons, + TrailingComma, + defaultPlaygroundState, +} from "../types"; +import { isJSONFilename, isTypeScriptFilename } from "../utils"; +import prettier, { Options as PrettierOptions } from "prettier"; +// @ts-expect-error +import parserBabel from "prettier/esm/parser-babel"; let settings = defaultPlaygroundState.settings; @@ -27,7 +39,7 @@ self.addEventListener("message", (e) => { lineWidth, indentStyle, indentWidth, - language: isTypeScriptFilename(filename) ? "ts" : "js", + filepath: filename, quoteStyle, quoteProperties, trailingComma, @@ -47,3 +59,75 @@ self.addEventListener("message", (e) => { console.error(`Unknown message ${e.data.type}.`); } }); + +function formatWithPrettier( + code: string, + options: { + lineWidth: number; + indentStyle: IndentStyle; + indentWidth: number; + filepath: string; + quoteStyle: QuoteStyle; + quoteProperties: QuoteProperties; + trailingComma: TrailingComma; + semicolons: Semicolons; + }, +): PrettierOutput { + try { + const prettierOptions: PrettierOptions = { + useTabs: options.indentStyle === IndentStyle.Tab, + tabWidth: options.indentWidth, + printWidth: options.lineWidth, + filepath: options.filepath, + plugins: [parserBabel], + parser: getPrettierParser(options.filepath), + singleQuote: options.quoteStyle === QuoteStyle.Single, + quoteProps: options.quoteProperties, + trailingComma: options.trailingComma, + semi: options.semicolons === Semicolons.Always, + }; + + // @ts-expect-error + const debug = prettier.__debug; + const document = debug.printToDoc(code, prettierOptions); + + // formatDoc must be before printDocToString because printDocToString mutates the document and breaks the ir + const ir = debug.formatDoc(document, { + parser: "babel", + plugins: [parserBabel], + }); + + const formattedCode = debug.printDocToString( + document, + prettierOptions, + ).formatted; + + return { + type: "SUCCESS", + code: formattedCode, + ir, + }; + } catch (err: unknown) { + if (err instanceof SyntaxError) { + return { + type: "ERROR", + stack: err.message, + }; + } else { + return { + type: "ERROR", + stack: (err as Error).stack ?? "", + }; + } + } +} + +function getPrettierParser(filename: string): string { + if (isTypeScriptFilename(filename)) { + return "babel-ts"; + } else if (isJSONFilename(filename)) { + return "json5"; + } else { + return "babel"; + } +} diff --git a/website/src/playground/workers/romeWorker.ts b/website/src/playground/workers/romeWorker.ts index 568837d2c6f..54980bdd0fb 100644 --- a/website/src/playground/workers/romeWorker.ts +++ b/website/src/playground/workers/romeWorker.ts @@ -15,6 +15,7 @@ import { RomeOutput, Semicolons, } from "../types"; +import { isJSONFilename } from "../utils"; let workspace: Workspace | null = null; let fileCounter = 0; @@ -189,10 +190,12 @@ self.addEventListener("message", async (e) => { path, }); - const controlFlowGraph = workspace.getControlFlowGraph({ - path, - cursor: cursorPosition, - }); + const controlFlowGraph = !isJSONFilename(filename) + ? workspace.getControlFlowGraph({ + path, + cursor: cursorPosition, + }) + : ""; const formatterIr = workspace.getFormatterIr({ path,