From 83dae006de0c32c7276956b80bc50b56a1e34ef0 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Tue, 28 Mar 2023 09:28:48 -0300 Subject: [PATCH] release: 12.0.0 (#4002) Co-authored-by: Victorien ELVINGER Co-authored-by: Emanuele Stoppa Co-authored-by: IWANABETHATGUY Co-authored-by: David Larlet <3556+davidbgk@users.noreply.github.com> Co-authored-by: realtimetodie Co-authored-by: Daiki Nishikawa Co-authored-by: JunkMeal <65283415+JunkMeal@users.noreply.github.com> --- .editorconfig | 2 +- .github/PULL_REQUEST_TEMPLATE.md | 10 + CHANGELOG.md | 131 +++ CONTRIBUTING.md | 94 +- Cargo.lock | 2 + crates/rome_cli/src/commands/help.rs | 17 +- crates/rome_cli/src/commands/rage.rs | 3 +- crates/rome_cli/tests/commands/check.rs | 7 +- .../snapshots/main_commands_rage/rage_ok.snap | 32 +- .../with_configuration.snap | 37 +- .../with_malformed_configuration.snap | 39 +- .../main_commands_rage/with_server_logs.snap | 32 +- .../nursery/use_exhaustive_dependencies.rs | 30 + crates/rome_service/src/diagnostics.rs | 4 + .../src/file_handlers/javascript.rs | 2 +- crates/rome_service/src/file_handlers/json.rs | 22 +- crates/rome_service/src/workspace/server.rs | 1 + editors/vscode/README.md | 18 +- editors/vscode/package.json | 3 +- .../vscode/scripts/update-nightly-version.mjs | 2 +- editors/vscode/src/commands/syntaxTree.ts | 24 +- editors/vscode/src/main.ts | 2 +- editors/vscode/src/session.ts | 4 +- editors/vscode/src/statusBar.ts | 2 +- editors/vscode/src/utils.ts | 2 +- npm/js-api/package.json | 5 +- npm/js-api/scripts/update-nightly-version.mjs | 2 +- npm/js-api/src/index.ts | 2 +- npm/js-api/tests/formatContent.test.ts | 2 +- npm/js-api/tests/lintContent.test.ts | 2 +- npm/js-api/tests/printDiagnostics.test.ts | 2 +- npm/rome/package.json | 2 +- npm/rome/scripts/generate-packages.mjs | 2 +- npm/rome/scripts/update-nightly-version.mjs | 2 +- rome.json | 3 + website/astro.config.ts | 10 +- website/package.json | 13 +- website/pnpm-lock.yaml | 1018 +++++++---------- website/src/components/Contributors.astro | 77 +- website/src/components/reference/Groups.astro | 15 +- website/src/components/reference/Groups.md | 9 - website/src/env.d.ts | 1 + website/src/frontend-scripts/docsearch.ts | 2 +- website/src/frontend-scripts/index.ts | 4 +- website/src/pages/analyzer/index.mdx | 54 + website/src/pages/cli.mdx | 31 +- website/src/pages/configuration.mdx | 113 +- website/src/pages/formatter/index.mdx | 6 + website/src/pages/guides/getting-started.mdx | 14 +- .../src/pages/internals/language_support.mdx | 4 +- website/src/pages/internals/versioning.mdx | 14 +- .../lint/rules/useExhaustiveDependencies.md | 31 + website/src/pages/linter/index.mdx | 12 +- website/src/playground/CodeMirror.tsx | 10 +- website/src/playground/Collapsible.tsx | 2 +- website/src/playground/Playground.tsx | 44 +- website/src/playground/PlaygroundLoader.tsx | 16 +- .../playground/components/DiagnosticsPane.tsx | 6 +- .../src/playground/components/Resizable.tsx | 4 +- .../playground/components/SettingsPane.tsx | 4 +- website/src/playground/components/Tabs.tsx | 2 +- website/src/playground/main.tsx | 2 +- .../src/playground/tabs/ControlFlowTab.tsx | 4 +- .../playground/tabs/DiagnosticsListTab.tsx | 8 +- .../src/playground/tabs/FormatterCodeTab.tsx | 2 +- .../src/playground/tabs/FormatterIRTab.tsx | 2 +- website/src/playground/tabs/SettingsTab.tsx | 10 +- website/src/playground/tabs/SyntaxTab.tsx | 6 +- website/src/playground/types.ts | 2 +- website/src/playground/utils.ts | 8 +- website/src/playground/workers/romeWorker.ts | 14 +- xtask/lintdoc/Cargo.toml | 2 + xtask/lintdoc/src/main.rs | 179 +-- 73 files changed, 1308 insertions(+), 993 deletions(-) delete mode 100644 website/src/components/reference/Groups.md create mode 100644 website/src/env.d.ts create mode 100644 website/src/pages/analyzer/index.mdx diff --git a/.editorconfig b/.editorconfig index 86bda6e8323..e38fe5895c9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,7 +10,7 @@ indent_size = 2 # YAML doesn't support hard tabs 🙃 # Templates that will be weird with hard tabs in the website editor -[{**.yml, .github/**.md, **.rs}] +[{**.yml, **.md, **.rs, **.mdx}] indent_style = space [*.rs] diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 023806a1802..a161aaf4c8d 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -18,6 +18,16 @@ +## Changelog + + + +- [ ] The PR requires a changelog line + ## Documentation -- `Accessibility`: Rules focused on preventing accessibility problems. -- `Complexity`: Rules that focus on inspecting complex code that could be simplified. -- `Correctness`: Rules that detect incorrect or useless code. -- `Security`: Rules that detect potential security flaws. -- `Style`: Rules enforcing a consistent way of writing your code. -- `Nursery`: New rules that are still under development. Nursery rules require explicit opt-in via configuration because they may still have bugs or performance problems. Nursery rules get promoted to other groups once they become stable or may be removed. Rules that belong to this group are not subject to semantic version. +
  • accessibility: Rules focused on preventing accessibility problems.
  • +
  • complexity: Rules that focus on inspecting complex code that could be simplified.
  • +
  • correctness: Rules that detect code that is guaranteed to be incorrect or useless.
  • +
  • performance: Rules catching ways your code could be written to run faster, or generally be more efficient.
  • +
  • security: Rules that detect potential security flaws.
  • +
  • style: Rules enforcing a consistent and idiomatic way of writing your code.
  • +
  • suspicious: Rules that detect code that is likely to be incorrect or useless.
  • +
  • nursery: New rules that are still under development. Nursery rules require explicit opt-in via configuration on stable versions because they may still have bugs or performance problems. They are enabled by default on nightly builds, but as they are unstable their diagnostic severity may be set to either error or warning, depending on whether we intend for the rule to be recommended or not when it eventually gets stabilized. Nursery rules get promoted to other groups once they become stable or may be removed. Rules that belong to this group are not subject to semantic version.
  • +
\ No newline at end of file diff --git a/website/src/components/reference/Groups.md b/website/src/components/reference/Groups.md deleted file mode 100644 index a93fdd796ef..00000000000 --- a/website/src/components/reference/Groups.md +++ /dev/null @@ -1,9 +0,0 @@ -{/** this file is auto generated, use `cargo lintdoc` to update it */} -- `Accessibility`: Rules focused on preventing accessibility problems. -- `Complexity`: Rules that focus on inspecting complex code that could be simplified. -- `Correctness`: Rules that detect code that is guaranteed to be incorrect or useless. -- `Performance`: Rules catching ways your code could be written to run faster, or generally be more efficient. -- `Security`: Rules that detect potential security flaws. -- `Style`: Rules enforcing a consistent and idiomatic way of writing your code. -- `Suspicious`: Rules that detect code that is likely to be incorrect or useless. -- `Nursery`: New rules that are still under development. Nursery rules require explicit opt-in via configuration on stable versions because they may still have bugs or performance problems. They are enabled by default on nightly builds, but as they are unstable their diagnostic severity may be set to either error or warning, depending on whether we intend for the rule to be recommended or not when it eventually gets stabilized. Nursery rules get promoted to other groups once they become stable or may be removed. Rules that belong to this group are not subject to semantic version. diff --git a/website/src/env.d.ts b/website/src/env.d.ts new file mode 100644 index 00000000000..f964fe0cffd --- /dev/null +++ b/website/src/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/website/src/frontend-scripts/docsearch.ts b/website/src/frontend-scripts/docsearch.ts index 3ef3e161164..6731d65d1b2 100644 --- a/website/src/frontend-scripts/docsearch.ts +++ b/website/src/frontend-scripts/docsearch.ts @@ -1,5 +1,5 @@ -import docsearch from "@docsearch/js"; import { matchesDark, setCurrentTheme } from "./util"; +import docsearch from "@docsearch/js"; const docsearchContainer = document.querySelector( "#docsearch-target", diff --git a/website/src/frontend-scripts/index.ts b/website/src/frontend-scripts/index.ts index c0acd7c32a7..61d7aee4f5d 100644 --- a/website/src/frontend-scripts/index.ts +++ b/website/src/frontend-scripts/index.ts @@ -1,7 +1,7 @@ -import { matchesDark, getCurrentTheme, setCurrentTheme } from "./util"; import "./mobile"; -import "./toc"; import "./package-manager-commands"; +import "./toc"; +import { getCurrentTheme, matchesDark, setCurrentTheme } from "./util"; //# Team list shuffle diff --git a/website/src/pages/analyzer/index.mdx b/website/src/pages/analyzer/index.mdx new file mode 100644 index 00000000000..ce5422594af --- /dev/null +++ b/website/src/pages/analyzer/index.mdx @@ -0,0 +1,54 @@ +--- +title: Analyzer +emoji: 🔍 +category: tools +description: What the Rome analyzer provides +--- + +# Analyzer + +Rome's analyzer provides a series of features that users can leverage. + + +### Imports Sorting + +Rome allows to sort import statement using [natural ordering](https://en.wikipedia.org/wiki/Natural_sort_order). + +This feature is opt-in via configuration: + +```json +{ + "organizeImports": { + "enabled": true + } +} +``` + +You can apply the sorting in two way: via LSP or CLI + +### Imports sorting via CLI + +Due the nature of the language, the sorting of imports is categorised as **unsafe**, and you can apply it using the `--apply-unsafe` option: + +```shell +rome check --apply-unsafe ./path/to/src +``` + +### Imports sorting via VSCode extension + + +The Rome VS Code extension has experimental support for imports sorting through the "Organize Imports" code action. By default this action can be run using the +Alt+O keyboard shortcut, or is accessible through the _Command Palette_ (Ctrl/++P) by selecting _Organize Imports_. + +You can add the following to your editor configuration if you want the action to run automatically on save instead of calling it manually: + +```json +{ + "editor.codeActionsOnSave":{ + "source.organizeImports.rome": true + } +} +``` + + + + diff --git a/website/src/pages/cli.mdx b/website/src/pages/cli.mdx index 80a176a8998..ad7f1d5dac6 100644 --- a/website/src/pages/cli.mdx +++ b/website/src/pages/cli.mdx @@ -11,17 +11,17 @@ description: Available commands and arguments in the Rome CLI. ### `rome init` -Helps you to set up Rome for a new project by guiding you through the creation of a new `rome.json` [configuration](/configuration) file. +Help you to set up Rome for a new project by guiding you through the creation of a new `rome.json` [configuration](/configuration) file. The command fails if the project already has a `rome.json` configuration file. ### `rome version` -Prints the version of the CLI and whether there's a server (daemon) connected +Print the version of the CLI and whether there's a server (daemon) connected ### `rome rage` -Prints information for debugging purpose +Print information for debugging purpose ### `rome lsp-proxy` @@ -31,15 +31,15 @@ This command is useful to interact with the Rome server when developing editors/ ### `rome format` -Runs the formatter on a set of files. +Run the formatter on a set of files. ### `rome check` -Runs the linter on a set of files and reports errors and warnings to the console. +Run the linter on a set of files and reports errors and warnings to the console. ### `rome ci` -Runs the linter and verifies the formatting of a set of files. It reports errors to the console. If any errors are found the process exits with a code of `1`. +Run the linter and verifies the formatting of a set of files. It reports errors to the console. If any errors are found the process exits with a code of `1`. This command is intended to be used in CI workflows. @@ -51,14 +51,16 @@ Start the Rome [daemon](/internals/architecture#daemon) server Stop the Rome [daemon](/internals/architecture#deamon) server -## Common Options +## Global Options -### `--colors=` +### `--colors` Set the formatting mode for markup: `off` prints everything as plain text, `force` forces the formatting of markup using ANSI even if the console output is determined to be incompatible +> Default: `force` + ### `--use-server` Connect to a running instance of the Rome daemon server @@ -69,14 +71,23 @@ The maximum allowed size for source code files in bytes. > Default: 1024*1024 bytes (1 MB) +### `--config-path` + +Tell Rome in which path to find the configuration file `rome.json`. + +> **Warning**: when passing `--config-path`, the auto discovery of the `rome.json` file is disabled. + +If Rome doesn't find a `rome.json`, it will abort the operation and exit with and error code. + + ## Global Options Use these flags to get information about the Rome CLI. ### `--version` -Prints the Rome version and exits. +Print the Rome version and exits. ### `--help` -Prints the help message and exits. +Print the help message and exits. diff --git a/website/src/pages/configuration.mdx b/website/src/pages/configuration.mdx index 361a7d3ae5e..19238530c2b 100644 --- a/website/src/pages/configuration.mdx +++ b/website/src/pages/configuration.mdx @@ -101,19 +101,63 @@ An array of Unix shell style patterns. ### `linter.rules.recommended` -Enables the [recommended rules](/lint/rules) for all categories. +Enables the [recommended rules](/lint/rules) for all groups. > Default: `true` -### `linter.rules.[category]` -Options that influence the rules of a single category. Rome supports the following categories: +### `linter.rules.all` + +Enable or disable all [rules](/lint/rules) for all groups. + +If `recommended` and `all` are both `true`, Rome will emit a diagnostic and fallback to its defaults. + + + +```json +{ + "linter": { + "enabled": true, + "rules": { + "all": true + } + } +} +``` + +It's also possible to combine this flag to enable/disable different rule groups: + + + +```json +{ + "linter": { + "enabled": true, + "rules": { + "all": true, + "style": { + "all": false + }, + "complexity": { + "all": false + } + } + } +} +``` + +In the previous example, Rome will enable all rules, exception for rules that belong to the `style` and `complexity` groups. + + +### `linter.rules.[group]` + +Options that influence the rules of a single group. Rome supports the following groups: -### `linter.rules.[category].recommended` +### `linter.rules.[group].recommended` -Enables the recommended rules for a single category. +Enables the recommended rules for a single group. Example: @@ -132,6 +176,28 @@ Example: } ``` + +### `linter.rules.[group].all` + +Enables all rules for a single group. + +Example: + + + +```json +{ + "linter": { + "enabled": true, + "rules": { + "nursery": { + "all": true + } + } + } +} +``` + ## `formatter` These options apply to all languages. There are additional language-specific formatting options below. @@ -192,6 +258,30 @@ How many characters can be written on a single line. > Default: `80` +## `organizeImports` + +### `organizeImports.enabled` (experimental) + +Enables Rome's sort imports. + +### `organizeImports.ignore` + + +A list of Unix shell style patterns. Rome ignores files and folders that +match these patterns. + + + +```json +{ + "organizeImports": { + "enable": true, + "ignore": ["scripts/*.js"] + } +} +``` +> Default: `false` + ## `javascript` These options apply only to JavaScript (and TypeScript) files. @@ -238,3 +328,16 @@ Example: } } ``` +### `javascript.globals` + +A list of global names that Rome should ignore (analyzer, linter, etc.) + + + +```json +{ + "javascript": { + "globals": ["$", "_", "externalVariable"] + } +} +``` diff --git a/website/src/pages/formatter/index.mdx b/website/src/pages/formatter/index.mdx index e942447e72c..6dd9243a83d 100644 --- a/website/src/pages/formatter/index.mdx +++ b/website/src/pages/formatter/index.mdx @@ -38,10 +38,16 @@ USAGE: INPUTS can be one or more filesystem path, each pointing to a single file or an entire directory to be searched recursively for supported files +EXAMPLES: + rome format ./scripts/file.js + rome format ./ + rome format ./src ./internal ./scripts + OPTIONS: --write Edit the files in place (beware!) instead of printing the diff to the console --skip-errors Skip over files containing syntax errors instead of emitting an error diagnostic. --max-diagnostics Cap the amount of diagnostics displayed (default: 50) + --config-path Set the filesystem path to the directory of the rome.json configuration file --verbose Print additional verbose advices on diagnostics --indent-style Change the indention character (default: tabs) --indent-size If the indentation style is set to spaces, determine how many spaces should be used for indentation (default: 2) diff --git a/website/src/pages/guides/getting-started.mdx b/website/src/pages/guides/getting-started.mdx index f5c55cca4e7..cf89e095497 100644 --- a/website/src/pages/guides/getting-started.mdx +++ b/website/src/pages/guides/getting-started.mdx @@ -24,13 +24,15 @@ The fastest way to download Rome is to use `npm` or your preferred package manag Run the following commands in a directory with a `package.json` file to install Rome. > **Note**: It is also possible to install Rome globally rather than locally. However, this is not recommended. +It's **highly recommended** to not use range operators when installing Rome. Check the [versioning page](/internals/versioning/) for more info. + You can now run Rome with: @@ -49,6 +51,10 @@ After running the `init` command, you'll now have a new `rome.json` file in your ```json { + "$schema": "./node_modules/rome/configuration_schema.json", + "organizeImports": { + "enabled": false + }, "linter": { "enabled": true, "rules": { @@ -87,7 +93,7 @@ Install our official [Rome VS Code extension](https://marketplace.visualstudio.c To make Rome the default formatter open a supported file (JavaScript or TypeScript) and: -* open the *Command Palette* (View or Command/Ctrl + Shift + P) +* open the *Command Palette* (View or Ctrl/++P) * select *Format Document With...* * select *Configure Default Formatter* * select *Rome*. diff --git a/website/src/pages/internals/language_support.mdx b/website/src/pages/internals/language_support.mdx index 365e09f1751..1fe49921205 100644 --- a/website/src/pages/internals/language_support.mdx +++ b/website/src/pages/internals/language_support.mdx @@ -12,7 +12,7 @@ description: Languages and features supported by Rome. | [JavaScript](#javascript-support) | | | | | [TypeScript](#typescript-support) | | | | | JSX | | | | -| JSON | (v12+) | (v12+) | 🚫 | +| JSON | | | ⌛️ | | HTML | 🚫 | 🚫 | 🚫 | | CSS | 🚫 | 🚫 | 🚫 | | Markdown | 🚫 | 🚫 | 🚫 | @@ -27,6 +27,6 @@ Rome supports only the official syntax. The team starts development of the new s ## TypeScript support -Rome supports TypeScript version 4.6. +Rome supports TypeScript version 4.7. Rome can handle programs using decorators but doesn't support formatting or linting decorators. diff --git a/website/src/pages/internals/versioning.mdx b/website/src/pages/internals/versioning.mdx index e6ec5c03eb5..3b69ef25582 100644 --- a/website/src/pages/internals/versioning.mdx +++ b/website/src/pages/internals/versioning.mdx @@ -7,6 +7,11 @@ description: How we version Rome. # Versioning +Fixes to lint rules, formatting layouts, etc. might prevent your scripts from passing. Due to the nature of these changes +it's **high recommended** to save the _exact_ version in your `package.json`, instead of using range operators. + +This methodology will make sure that your script won't fail unexpectedly. + ## Semantic Versioning Rome follows [semantic versioning](https://semver.org/). Due to the nature of Rome as a toolchain, it can be unclear what changes are considered major, minor, or patch. That's why Rome uses the following versioning guide: @@ -23,6 +28,7 @@ Rome follows [semantic versioning](https://semver.org/). Due to the nature of Ro * Increase or change in test coverage * Improving the wording of diagnostics or fixing the rendering of diagnostics. * Re-releases after a failed release +* Changing the formatting of established syntax. ### Minor Release @@ -31,13 +37,13 @@ Rome follows [semantic versioning](https://semver.org/). Due to the nature of Ro * Removal of recommended rules * Deprecation of existing rules * Adding new configuration optional configuration options that do not change the formatting or report more lint errors. +* Adding a new recommended lint rule or promoting an existing lint rule from the nursery group to a recommended lint rule in a stable group. +* Removal of a non-*nursery* rule or demoting a rule to the *nursery* group. ### Major Release -* Adding a new recommended lint rule or promoting an existing lint rule from the nursery group to a recommended lint rule in a stable group. -* Changing the formatting of established syntax. * Changes to the configuration that result in different formatting or more reported lint errors (adding/removing options, changing the default value) -* Removal of a non-*nursery* rule or demoting a rule to the *nursery* group. * Changes to Rome's public API +* Promotion of new features or tools that require some spotlight ## Visual Studio Code Extension @@ -45,5 +51,3 @@ Visual Studio Code [doesn't support pre-release tags](https://code.visualstudio. * Stable releases use even version numbers: 10, 12, 14, 16, ... * Previews use odd version numbers: 11, 13, 15, 17, ... -## Release Schedule -Our goal is to release a new version of Rome every four weeks. diff --git a/website/src/pages/lint/rules/useExhaustiveDependencies.md b/website/src/pages/lint/rules/useExhaustiveDependencies.md index 3ada5569ee2..4df13eaa77a 100644 --- a/website/src/pages/lint/rules/useExhaustiveDependencies.md +++ b/website/src/pages/lint/rules/useExhaustiveDependencies.md @@ -166,6 +166,37 @@ function component() { } ``` +## Options + +Allows to specify custom hooks - from libraries or internal projects - that can be considered stable. + +``` +{ + "//": "...", + "options": { + "hooks": [ + ["useLocation", 0, 1], + ["useQuery", 1, 0] + ] + } +} +``` + +The following items mean: + +1. the name of the hook +2. the index of the closure +3. the index of the array of dependencies + +Given the previous example, your hooks be used like this: + +```jsx +function Foo() { + const location = useLocation(() => {}, []); + const query = useQuery([], () => {}); +} +``` + ## Related links - [Disable a rule](/linter/#disable-a-lint-rule) diff --git a/website/src/pages/linter/index.mdx b/website/src/pages/linter/index.mdx index 761fb105e29..a9ca8a16701 100644 --- a/website/src/pages/linter/index.mdx +++ b/website/src/pages/linter/index.mdx @@ -25,12 +25,18 @@ Rome Check: Run the linter on a set of files USAGE: rome check - INPUTS can be one or more filesystem path, each pointing to a single file or an entire directory to be searched recursively for supported files + INPUTS can be one or more filesystem paths, each pointing to a single file or an entire directory. + +EXAMPLES: + rome check ./scripts/file.js + rome check ./ + rome check ./src ./internal ./scripts OPTIONS: --apply Apply safe fixes - --apply-suggested Apply safe and suggested fixes - --max-diagnostics Cap the amount of diagnostics displayed - default 20 + --apply-unsafe Apply safe and unsafe fixes + --max-diagnostics Cap the amount of diagnostics displayed (default: 20) + --config-path Set the filesystem path to the directory of the rome.json configuration file --verbose Print additional verbose advices on diagnostics ``` diff --git a/website/src/playground/CodeMirror.tsx b/website/src/playground/CodeMirror.tsx index 7369e2d5ba7..a2366ecb344 100644 --- a/website/src/playground/CodeMirror.tsx +++ b/website/src/playground/CodeMirror.tsx @@ -1,15 +1,15 @@ +import { useTheme } from "./utils"; +import type { Diagnostic as CodeMirrorDiagnostic } from "@codemirror/lint"; +import { lintGutter, setDiagnostics } from "@codemirror/lint"; +import type { Extension } from "@codemirror/state"; +import { EditorView } from "@codemirror/view"; import type { Diagnostic as RomeDiagnostic } from "@rometools/wasm-web"; import type { ReactCodeMirrorProps, ReactCodeMirrorRef, } from "@uiw/react-codemirror"; -import type { Extension } from "@codemirror/state"; -import type { Diagnostic as CodeMirrorDiagnostic } from "@codemirror/lint"; -import { EditorView } from "@codemirror/view"; import RealCodeMirror from "@uiw/react-codemirror"; import { forwardRef, useEffect, useMemo, useState } from "react"; -import { useTheme } from "./utils"; -import { lintGutter, setDiagnostics } from "@codemirror/lint"; interface Props extends ReactCodeMirrorProps { diagnostics?: RomeDiagnostic[]; diff --git a/website/src/playground/Collapsible.tsx b/website/src/playground/Collapsible.tsx index 3eaf010defa..62d9abcb437 100644 --- a/website/src/playground/Collapsible.tsx +++ b/website/src/playground/Collapsible.tsx @@ -1,5 +1,5 @@ -import { useState } from "react"; import { classnames } from "./utils"; +import { useState } from "react"; interface Props { className?: string; diff --git a/website/src/playground/Playground.tsx b/website/src/playground/Playground.tsx index 85c12f3a9d3..97f7455e618 100644 --- a/website/src/playground/Playground.tsx +++ b/website/src/playground/Playground.tsx @@ -1,24 +1,16 @@ -import type { PlaygroundProps, RomeAstSyntacticData } from "./types"; -import type { ReactCodeMirrorRef } from "@uiw/react-codemirror"; 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 DiagnosticsPane from "./components/DiagnosticsPane"; +import Resizable from "./components/Resizable"; import SettingsPane from "./components/SettingsPane"; -import { - createRef, - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from "react"; -import { EditorSelection } from "@codemirror/state"; -import SyntaxTab from "./tabs/SyntaxTab"; +import Tabs from "./components/Tabs"; import ControlFlowTab from "./tabs/ControlFlowTab"; +import DiagnosticsConsoleTab from "./tabs/DiagnosticsConsoleTab"; +import DiagnosticsListTab from "./tabs/DiagnosticsListTab"; import FormatterCodeTab from "./tabs/FormatterCodeTab"; import FormatterIRTab from "./tabs/FormatterIRTab"; +import SettingsTab from "./tabs/SettingsTab"; +import SyntaxTab from "./tabs/SyntaxTab"; +import type { PlaygroundProps, RomeAstSyntacticData } from "./types"; import { getCurrentCode, getFileState, @@ -27,12 +19,20 @@ import { isTypeScriptFilename, useWindowSize, } from "./utils"; -import Resizable from "./components/Resizable"; -import DiagnosticsPane from "./components/DiagnosticsPane"; -import Tabs from "./components/Tabs"; -import DiagnosticsConsoleTab from "./tabs/DiagnosticsConsoleTab"; -import DiagnosticsListTab from "./tabs/DiagnosticsListTab"; -import SettingsTab from "./tabs/SettingsTab"; +import { javascript } from "@codemirror/lang-javascript"; +import { json } from "@codemirror/lang-json"; +import { EditorSelection } from "@codemirror/state"; +import type { ViewUpdate } from "@codemirror/view"; +import type { ReactCodeMirrorRef } from "@uiw/react-codemirror"; +import * as codeMirrorLangRomeAST from "codemirror-lang-rome-ast"; +import { + createRef, + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; export default function PlaygroundLoader({ setPlaygroundState, diff --git a/website/src/playground/PlaygroundLoader.tsx b/website/src/playground/PlaygroundLoader.tsx index b81f263c633..051f8e83f91 100644 --- a/website/src/playground/PlaygroundLoader.tsx +++ b/website/src/playground/PlaygroundLoader.tsx @@ -1,17 +1,18 @@ -import { useEffect, useState, useRef, SetStateAction, Dispatch } from "react"; +import Playground from "./Playground"; +import LoadingScreen from "./components/LoadingScreen"; import { - defaultPlaygroundState, - emptyPrettierOutput, - emptyRomeOutput, IndentStyle, + LintRules, LoadingState, PlaygroundSettings, PlaygroundState, QuoteProperties, QuoteStyle, - TrailingComma, Semicolons, - LintRules, + TrailingComma, + defaultPlaygroundState, + emptyPrettierOutput, + emptyRomeOutput, } from "./types"; import { createLocalStorage, @@ -25,8 +26,7 @@ import { isTypeScriptFilename, normalizeFilename, } from "./utils"; -import Playground from "./Playground"; -import LoadingScreen from "./components/LoadingScreen"; +import { Dispatch, SetStateAction, useEffect, useRef, useState } from "react"; function throttle(callback: () => void): () => void { const timeout = setTimeout(callback, 100); diff --git a/website/src/playground/components/DiagnosticsPane.tsx b/website/src/playground/components/DiagnosticsPane.tsx index 06bf242c64a..697a61b4050 100644 --- a/website/src/playground/components/DiagnosticsPane.tsx +++ b/website/src/playground/components/DiagnosticsPane.tsx @@ -1,9 +1,9 @@ -import type { Diagnostic } from "@rometools/wasm-web"; -import type { ReactCodeMirrorRef } from "@uiw/react-codemirror"; -import { useState } from "react"; import DiagnosticsConsoleTab from "../tabs/DiagnosticsConsoleTab"; import DiagnosticsListTab from "../tabs/DiagnosticsListTab"; import Tabs from "./Tabs"; +import type { Diagnostic } from "@rometools/wasm-web"; +import type { ReactCodeMirrorRef } from "@uiw/react-codemirror"; +import { useState } from "react"; interface Props { editorRef: React.RefObject; diff --git a/website/src/playground/components/Resizable.tsx b/website/src/playground/components/Resizable.tsx index 1b53e26ea25..98b474a0cdc 100644 --- a/website/src/playground/components/Resizable.tsx +++ b/website/src/playground/components/Resizable.tsx @@ -1,6 +1,6 @@ -import type React from "react"; -import { useMemo, useState, createRef, useEffect } from "react"; import { createLocalStorage } from "../utils"; +import type React from "react"; +import { createRef, useEffect, useMemo, useState } from "react"; interface Props { name: string; diff --git a/website/src/playground/components/SettingsPane.tsx b/website/src/playground/components/SettingsPane.tsx index 824ffa297ea..cf0e42d63ad 100644 --- a/website/src/playground/components/SettingsPane.tsx +++ b/website/src/playground/components/SettingsPane.tsx @@ -1,7 +1,7 @@ import type { SettingsTabProps } from "../tabs/SettingsTab"; -import { useState, useEffect } from "react"; -import { classNames, createLocalStorage } from "../utils"; import SettingsTab from "../tabs/SettingsTab"; +import { classNames, createLocalStorage } from "../utils"; +import { useEffect, useState } from "react"; const isCollapsedStore = createLocalStorage("settings-collapsed"); diff --git a/website/src/playground/components/Tabs.tsx b/website/src/playground/components/Tabs.tsx index fcab60c483d..3171877d7c6 100644 --- a/website/src/playground/components/Tabs.tsx +++ b/website/src/playground/components/Tabs.tsx @@ -1,5 +1,5 @@ -import type React from "react"; import { classnames } from "../utils"; +import type React from "react"; interface Tab { key: string; diff --git a/website/src/playground/main.tsx b/website/src/playground/main.tsx index 0902d20ed15..a5fe22b4c90 100644 --- a/website/src/playground/main.tsx +++ b/website/src/playground/main.tsx @@ -1,6 +1,6 @@ +import PlaygroundLoader from "./PlaygroundLoader"; import React from "react"; import ReactDOM from "react-dom"; -import PlaygroundLoader from "./PlaygroundLoader"; ReactDOM.render( diff --git a/website/src/playground/tabs/ControlFlowTab.tsx b/website/src/playground/tabs/ControlFlowTab.tsx index 1095fb3138b..09b1503d7d5 100644 --- a/website/src/playground/tabs/ControlFlowTab.tsx +++ b/website/src/playground/tabs/ControlFlowTab.tsx @@ -1,6 +1,6 @@ -import { useMemo } from "react"; -import mermaid from "mermaid"; import { useTheme } from "../utils"; +import mermaid from "mermaid"; +import { useMemo } from "react"; interface Props { graph: string; diff --git a/website/src/playground/tabs/DiagnosticsListTab.tsx b/website/src/playground/tabs/DiagnosticsListTab.tsx index 410d7b78e7f..b09e0839d55 100644 --- a/website/src/playground/tabs/DiagnosticsListTab.tsx +++ b/website/src/playground/tabs/DiagnosticsListTab.tsx @@ -1,9 +1,9 @@ -import type { ReactCodeMirrorRef } from "@uiw/react-codemirror"; -import type { Diagnostic } from "@rometools/wasm-web"; -import { EditorSelection } from "@codemirror/state"; -import infoIcon from "../../svg/info.svg"; import errorIcon from "../../svg/error.svg"; +import infoIcon from "../../svg/info.svg"; import warningIcon from "../../svg/warning.svg"; +import { EditorSelection } from "@codemirror/state"; +import type { Diagnostic } from "@rometools/wasm-web"; +import type { ReactCodeMirrorRef } from "@uiw/react-codemirror"; interface Props { editorRef: React.RefObject; diff --git a/website/src/playground/tabs/FormatterCodeTab.tsx b/website/src/playground/tabs/FormatterCodeTab.tsx index 8a2ab7eb39b..77905f75552 100644 --- a/website/src/playground/tabs/FormatterCodeTab.tsx +++ b/website/src/playground/tabs/FormatterCodeTab.tsx @@ -2,9 +2,9 @@ import CodeMirror from "../CodeMirror"; import Collapsible from "../Collapsible"; import PrettierHeader from "../components/PrettierHeader"; import RomeHeader from "../components/RomeHeader"; -import fastDiff from "fast-diff"; import type { PrettierOutput } from "../types"; import type { Extension } from "@codemirror/state"; +import fastDiff from "fast-diff"; interface Props { prettier: PrettierOutput; diff --git a/website/src/playground/tabs/FormatterIRTab.tsx b/website/src/playground/tabs/FormatterIRTab.tsx index 469e0e93503..a199c095182 100644 --- a/website/src/playground/tabs/FormatterIRTab.tsx +++ b/website/src/playground/tabs/FormatterIRTab.tsx @@ -2,8 +2,8 @@ import CodeMirror from "../CodeMirror"; import Collapsible from "../Collapsible"; import PrettierHeader from "../components/PrettierHeader"; import RomeHeader from "../components/RomeHeader"; -import { romeAst as RomeFormatterIr } from "lang-rome-formatter-ir"; import type { PrettierOutput } from "../types"; +import { romeAst as RomeFormatterIr } from "lang-rome-formatter-ir"; interface Props { prettier: PrettierOutput; diff --git a/website/src/playground/tabs/SettingsTab.tsx b/website/src/playground/tabs/SettingsTab.tsx index ea5d0f75c49..90e5b32a826 100644 --- a/website/src/playground/tabs/SettingsTab.tsx +++ b/website/src/playground/tabs/SettingsTab.tsx @@ -8,18 +8,18 @@ import { SourceType, TrailingComma, } from "../types"; -import type { Dispatch, SetStateAction } from "react"; -import React, { useState } from "react"; import { - modifyFilename, + classnames, createPlaygroundSettingsSetter, + getFileState, isJSXFilename, isScriptFilename, isTypeScriptFilename, - classnames, - getFileState, + modifyFilename, normalizeFilename, } from "../utils"; +import type { Dispatch, SetStateAction } from "react"; +import React, { useState } from "react"; export interface SettingsTabProps { state: PlaygroundState; diff --git a/website/src/playground/tabs/SyntaxTab.tsx b/website/src/playground/tabs/SyntaxTab.tsx index 52e35ea66c9..f9248452432 100644 --- a/website/src/playground/tabs/SyntaxTab.tsx +++ b/website/src/playground/tabs/SyntaxTab.tsx @@ -1,8 +1,8 @@ -import type { ReactCodeMirrorRef } from "@uiw/react-codemirror"; -import React from "react"; import CodeMirror from "../CodeMirror"; -import { romeAst } from "codemirror-lang-rome-ast"; import Collapsible from "../Collapsible"; +import type { ReactCodeMirrorRef } from "@uiw/react-codemirror"; +import { romeAst } from "codemirror-lang-rome-ast"; +import React from "react"; interface Props { ast: string; diff --git a/website/src/playground/types.ts b/website/src/playground/types.ts index 16989ebfa5a..9035bef538a 100644 --- a/website/src/playground/types.ts +++ b/website/src/playground/types.ts @@ -1,6 +1,6 @@ import type { Diagnostic } from "@rometools/wasm-web"; -import type { Dispatch, SetStateAction } from "react"; import type { parser } from "codemirror-lang-rome-ast"; +import type { Dispatch, SetStateAction } from "react"; export enum IndentStyle { Tab = "tab", diff --git a/website/src/playground/utils.ts b/website/src/playground/utils.ts index 4e8703d7721..a80e66611ac 100644 --- a/website/src/playground/utils.ts +++ b/website/src/playground/utils.ts @@ -1,13 +1,13 @@ -import { Dispatch, SetStateAction, useEffect, useState } from "react"; import type { ThemeName } from "../frontend-scripts/util"; +import { getCurrentTheme } from "../frontend-scripts/util"; import { - PlaygroundState, + PlaygroundFileState, PlaygroundSettings, + PlaygroundState, emptyPrettierOutput, emptyRomeOutput, - PlaygroundFileState, } from "./types"; -import { getCurrentTheme } from "../frontend-scripts/util"; +import { Dispatch, SetStateAction, useEffect, useState } from "react"; export function classNames( ...classes: (string | undefined | boolean)[] diff --git a/website/src/playground/workers/romeWorker.ts b/website/src/playground/workers/romeWorker.ts index b1cd314c14f..ca6bb0a821b 100644 --- a/website/src/playground/workers/romeWorker.ts +++ b/website/src/playground/workers/romeWorker.ts @@ -1,10 +1,3 @@ -import init, { - Configuration, - DiagnosticPrinter, - RomePath, - RuleCategories, - Workspace, -} from "@rometools/wasm-web"; import { IndentStyle, LintRules, @@ -16,6 +9,13 @@ import { Semicolons, } from "../types"; import { isJSONFilename } from "../utils"; +import init, { + Configuration, + DiagnosticPrinter, + RomePath, + RuleCategories, + Workspace, +} from "@rometools/wasm-web"; let workspace: Workspace | null = null; let fileCounter = 0; diff --git a/xtask/lintdoc/Cargo.toml b/xtask/lintdoc/Cargo.toml index 8346e3db66c..2cccc298781 100644 --- a/xtask/lintdoc/Cargo.toml +++ b/xtask/lintdoc/Cargo.toml @@ -12,6 +12,8 @@ rome_diagnostics = { path = "../../crates/rome_diagnostics" } rome_js_analyze = { path = "../../crates/rome_js_analyze" } rome_js_parser = { path = "../../crates/rome_js_parser" } rome_js_syntax = { path = "../../crates/rome_js_syntax" } +rome_json_parser = { path = "../../crates/rome_json_parser" } +rome_json_syntax = { path = "../../crates/rome_json_syntax" } rome_service = { path = "../../crates/rome_service" } rome_formatter = { path = "../../crates/rome_formatter" } pulldown-cmark = { version = "0.9", default-features = false } diff --git a/xtask/lintdoc/src/main.rs b/xtask/lintdoc/src/main.rs index 578090be58d..571ee1f392b 100644 --- a/xtask/lintdoc/src/main.rs +++ b/xtask/lintdoc/src/main.rs @@ -25,7 +25,7 @@ use xtask::{glue::fs2, *}; fn main() -> Result<()> { let root = project_root().join("website/src/pages/lint/rules"); - let reference_groups = project_root().join("website/src/components/reference/Groups.md"); + let reference_groups = project_root().join("website/src/components/reference/Groups.astro"); // Clear the rules directory ignoring "not found" errors if let Err(err) = fs2::remove_dir_all(&root) { @@ -97,8 +97,9 @@ fn main() -> Result<()> { writeln!( reference_buffer, - "{{/** this file is auto generated, use `cargo lintdoc` to update it */}}" + "" )?; + write!(reference_buffer, "
    ")?; for (group, rules) in groups { generate_group(group, rules, &root, &mut index, &mut errors)?; generate_reference(group, &mut reference_buffer)?; @@ -106,7 +107,7 @@ fn main() -> Result<()> { generate_group("nursery", nursery_rules, &root, &mut index, &mut errors)?; generate_reference("nursery", &mut reference_buffer)?; - + write!(reference_buffer, "
")?; if !errors.is_empty() { bail!( "failed to generate documentation pages for the following rules:\n{}", @@ -242,13 +243,15 @@ fn parse_documentation( // re-generating the language ID from the source type write!(content, "```")?; if !meta.is_empty() { - match test.source_type.language() { - Language::JavaScript => write!(content, "js")?, - Language::TypeScript { .. } => write!(content, "ts")?, - } - match test.source_type.variant() { - LanguageVariant::Standard => {} - LanguageVariant::Jsx => write!(content, "x")?, + if let BlockType::Js(source_type) = test.block_type { + match source_type.language() { + Language::JavaScript => write!(content, "js")?, + Language::TypeScript { .. } => write!(content, "ts")?, + } + match source_type.variant() { + LanguageVariant::Standard => {} + LanguageVariant::Jsx => write!(content, "x")?, + } } } writeln!(content)?; @@ -397,8 +400,13 @@ fn parse_documentation( Ok(summary) } +enum BlockType { + Js(SourceType), + Json, +} + struct CodeBlockTest { - source_type: SourceType, + block_type: BlockType, expect_diagnostic: bool, } @@ -414,7 +422,7 @@ impl FromStr for CodeBlockTest { .filter(|token| !token.is_empty()); let mut test = CodeBlockTest { - source_type: SourceType::default(), + block_type: BlockType::Js(SourceType::default()), expect_diagnostic: false, }; @@ -422,19 +430,21 @@ impl FromStr for CodeBlockTest { match token { // Determine the language, using the same list of extensions as `compute_source_type_from_path_or_extension` "cjs" => { - test.source_type = SourceType::js_module().with_module_kind(ModuleKind::Script); + test.block_type = + BlockType::Js(SourceType::js_module().with_module_kind(ModuleKind::Script)); } "js" | "mjs" | "jsx" => { - test.source_type = SourceType::jsx(); + test.block_type = BlockType::Js(SourceType::jsx()); } "ts" | "mts" => { - test.source_type = SourceType::ts(); + test.block_type = BlockType::Js(SourceType::ts()); } "cts" => { - test.source_type = SourceType::ts().with_module_kind(ModuleKind::Script); + test.block_type = + BlockType::Js(SourceType::ts().with_module_kind(ModuleKind::Script)); } "tsx" => { - test.source_type = SourceType::tsx(); + test.block_type = BlockType::Js(SourceType::tsx()); } // Other attributes @@ -442,6 +452,10 @@ impl FromStr for CodeBlockTest { test.expect_diagnostic = true; } + "json" => { + test.block_type = BlockType::Json; + } + _ => { bail!("unknown code block attribute {token:?}") } @@ -518,68 +532,84 @@ fn assert_lint( Ok(()) }; - let parse = rome_js_parser::parse(code, test.source_type); - - if parse.has_errors() { - for diag in parse.into_diagnostics() { - let error = diag - .with_file_path(file.clone()) - .with_file_source_code(code); - write_diagnostic(code, error)?; - } - } else { - let root = parse.tree(); - - let settings = WorkspaceSettings::default(); - - let rule_filter = RuleFilter::Rule(group, rule); - let filter = AnalysisFilter { - enabled_rules: Some(slice::from_ref(&rule_filter)), - ..AnalysisFilter::default() - }; - - let options = AnalyzerOptions::default(); - let (_, diagnostics) = analyze(&root, filter, &options, |signal| { - if let Some(mut diag) = signal.diagnostic() { - let category = diag.category().expect("linter diagnostic has no code"); - let severity = settings.get_severity_from_rule_code(category).expect( - "If you see this error, it means you need to run cargo codegen-configuration", - ); + match test.block_type { + BlockType::Js(source_type) => { + let parse = rome_js_parser::parse(code, source_type); - for action in signal.actions() { - if !action.is_suppression() { - diag = diag.add_code_suggestion(action.into()); - } + if parse.has_errors() { + for diag in parse.into_diagnostics() { + let error = diag + .with_file_path(file.clone()) + .with_file_source_code(code); + write_diagnostic(code, error)?; } + } else { + let root = parse.tree(); + + let settings = WorkspaceSettings::default(); + + let rule_filter = RuleFilter::Rule(group, rule); + let filter = AnalysisFilter { + enabled_rules: Some(slice::from_ref(&rule_filter)), + ..AnalysisFilter::default() + }; + + let options = AnalyzerOptions::default(); + let (_, diagnostics) = analyze(&root, filter, &options, |signal| { + if let Some(mut diag) = signal.diagnostic() { + let category = diag.category().expect("linter diagnostic has no code"); + let severity = settings.get_severity_from_rule_code(category).expect( + "If you see this error, it means you need to run cargo codegen-configuration", + ); + + for action in signal.actions() { + if !action.is_suppression() { + diag = diag.add_code_suggestion(action.into()); + } + } + + let error = diag + .with_severity(severity) + .with_file_path(file.clone()) + .with_file_source_code(code); + let res = write_diagnostic(code, error); + + // Abort the analysis on error + if let Err(err) = res { + return ControlFlow::Break(err); + } + } - let error = diag - .with_severity(severity) - .with_file_path(file.clone()) - .with_file_source_code(code); - let res = write_diagnostic(code, error); + ControlFlow::Continue(()) + }); - // Abort the analysis on error - if let Err(err) = res { - return ControlFlow::Break(err); + // Result is Some(_) if analysis aborted with an error + for diagnostic in diagnostics { + write_diagnostic(code, diagnostic)?; } } - ControlFlow::Continue(()) - }); - - // Result is Some(_) if analysis aborted with an error - for diagnostic in diagnostics { - write_diagnostic(code, diagnostic)?; + if test.expect_diagnostic { + // Fail the test if the analysis didn't emit any diagnostic + ensure!( + diagnostic_count == 1, + "analysis returned no diagnostics.\n code snippet:\n {}", + code + ); + } + } + BlockType::Json => { + let parse = rome_json_parser::parse_json(code); + + if parse.has_errors() { + for diag in parse.into_diagnostics() { + let error = diag + .with_file_path(file.clone()) + .with_file_source_code(code); + write_diagnostic(code, error)?; + } + } } - } - - if test.expect_diagnostic { - // Fail the test if the analysis didn't emit any diagnostic - ensure!( - diagnostic_count == 1, - "analysis returned no diagnostics.\n code snippet:\n {}", - code - ); } Ok(()) @@ -589,7 +619,12 @@ fn generate_reference(group: &'static str, buffer: &mut dyn io::Write) -> io::Re let (group_name, description) = extract_group_metadata(group); let description = markup_to_string(&description.to_owned()); let description = description.replace('\n', " "); - writeln!(buffer, "- `{}`: {}", group_name, description) + writeln!( + buffer, + "
  • {}: {}
  • ", + group_name.to_lowercase(), + description + ) } fn extract_group_metadata(group: &str) -> (&str, Markup) {