diff --git a/.github/workflows/publish-wasm.yml b/.github/workflows/publish-wasm.yml new file mode 100644 index 0000000000000..2cab1a873c65b --- /dev/null +++ b/.github/workflows/publish-wasm.yml @@ -0,0 +1,55 @@ +# Build and publish ruff-api for wasm. +# +# Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a publish +# job within `cargo-dist`. +name: "Build and publish wasm" + +on: + workflow_dispatch: + workflow_call: + inputs: + plan: + required: true + type: string + +env: + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + CARGO_TERM_COLOR: always + RUSTUP_MAX_RETRIES: 10 + +jobs: + ruff_wasm: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + strategy: + matrix: + target: [web, bundler, nodejs] + fail-fast: false + steps: + - uses: actions/checkout@v4 + - name: "Install Rust toolchain" + run: rustup target add wasm32-unknown-unknown + - uses: jetli/wasm-pack-action@v0.4.0 + - uses: jetli/wasm-bindgen-action@v0.2.0 + - name: "Run wasm-pack build" + run: wasm-pack build --target ${{ matrix.target }} crates/ruff_wasm + - name: "Rename generated package" + run: | # Replace the package name w/ jq + jq '.name="@astral-sh/ruff-wasm-${{ matrix.target }}"' crates/ruff_wasm/pkg/package.json > /tmp/package.json + mv /tmp/package.json crates/ruff_wasm/pkg + - run: cp LICENSE crates/ruff_wasm/pkg # wasm-pack does not put the LICENSE file in the pkg + - uses: actions/setup-node@v4 + with: + node-version: 18 + registry-url: "https://registry.npmjs.org" + - name: "Publish (dry-run)" + if: ${{ inputs.plan == '' || fromJson(inputs.plan).announcement_tag_is_implicit }} + run: npm publish --dry-run crates/ruff_wasm/pkg + - name: "Publish" + if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }} + run: npm publish --provenance --access public crates/ruff_wasm/pkg + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7132970c36a57..4791aa237a92f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -214,16 +214,31 @@ jobs: "id-token": "write" "packages": "write" + custom-publish-wasm: + needs: + - plan + - host + if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }} + uses: ./.github/workflows/publish-wasm.yml + with: + plan: ${{ needs.plan.outputs.val }} + secrets: inherit + # publish jobs get escalated permissions + permissions: + "id-token": "write" + "packages": "write" + # Create a GitHub Release while uploading all files to it announce: needs: - plan - host - custom-publish-pypi + - custom-publish-wasm # use "always() && ..." to allow us to wait for all publish jobs while # still allowing individual publish jobs to skip themselves (for prereleases). # "host" however must run to completion, no skipping allowed! - if: ${{ always() && needs.host.result == 'success' && (needs.custom-publish-pypi.result == 'skipped' || needs.custom-publish-pypi.result == 'success') }} + if: ${{ always() && needs.host.result == 'success' && (needs.custom-publish-pypi.result == 'skipped' || needs.custom-publish-pypi.result == 'success') && (needs.custom-publish-wasm.result == 'skipped' || needs.custom-publish-wasm.result == 'success') }} runs-on: "ubuntu-20.04" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Cargo.lock b/Cargo.lock index 77ac3ebd97838..efffff748f4dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2498,7 +2498,7 @@ dependencies = [ [[package]] name = "ruff_wasm" -version = "0.0.0" +version = "0.5.2" dependencies = [ "console_error_panic_hook", "console_log", diff --git a/Cargo.toml b/Cargo.toml index 0cb4f2e88ea17..761b3c5f3d39c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -272,7 +272,7 @@ build-local-artifacts = false # Local artifacts jobs to run in CI local-artifacts-jobs = ["./build-binaries", "./build-docker"] # Publish jobs to run in CI -publish-jobs = ["./publish-pypi"] +publish-jobs = ["./publish-pypi", "./publish-wasm"] # Announcement jobs to run in CI post-announce-jobs = ["./notify-dependents", "./publish-docs", "./publish-playground"] # Custom permissions for GitHub Jobs diff --git a/crates/ruff_wasm/Cargo.toml b/crates/ruff_wasm/Cargo.toml index 3761f63e1e67f..70abe3e7a32a2 100644 --- a/crates/ruff_wasm/Cargo.toml +++ b/crates/ruff_wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ruff_wasm" -version = "0.0.0" +version = "0.5.2" publish = false authors = { workspace = true } edition = { workspace = true } diff --git a/crates/ruff_wasm/README.md b/crates/ruff_wasm/README.md new file mode 100644 index 0000000000000..59f5b486b194e --- /dev/null +++ b/crates/ruff_wasm/README.md @@ -0,0 +1,51 @@ +# Ruff WASM + +> **⚠️ WARNING: This API is experimental and may change at any time** + +[**Docs**](https://docs.astral.sh/ruff/) | [**Playground**](https://play.ruff.rs/) + +An extremely fast Python linter and code formatter, written in Rust. + +This is a WASM version of the Ruff API which can be used to lint/format Python in a browser environment. + +There are multiple versions for the different wasm-pack targets. See [here](https://rustwasm.github.io/docs/wasm-bindgen/reference/deployment.html) for more info on targets. + +- [Bundler](https://www.npmjs.com/package/@astral-sh/ruff-wasm-bundler) +- [Web](https://www.npmjs.com/package/@astral-sh/ruff-wasm-web) +- [Node.js](https://www.npmjs.com/package/@astral-sh/ruff-wasm-nodejs) + +## Usage + +This example uses the wasm-pack web target and is known to work with Vite. + +```ts +import init, { Workspace, type Diagnostic } from '@astral-sh/ruff-api'; + +const exampleDocument = `print('hello'); print("world")` + +await init(); // Initializes WASM module + +// These are default settings just to illustrate configuring Ruff +// Settings info: https://docs.astral.sh/ruff/settings +const workspace = new Workspace({ + 'line-length': 88, + 'indent-width': 4, + format: { + 'indent-style': 'space', + 'quote-style': 'double', + }, + lint: { + select: [ + 'E4', + 'E7', + 'E9', + 'F' + ], + }, +}); + +// Will contain 1 diagnostic code for E702: Multiple statements on one line +const diagnostics: Diagnostic[] = workspace.check(exampleDocument); + +const formatted = workspace.format(exampleDocument); +``` diff --git a/pyproject.toml b/pyproject.toml index 326eb0121a260..fc4f073b38bd5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -108,5 +108,6 @@ version_files = [ "docs/integrations.md", "crates/ruff/Cargo.toml", "crates/ruff_linter/Cargo.toml", + "crates/ruff_wasm/Cargo.toml", "scripts/benchmarks/pyproject.toml", ]