From a1134472e095249646e7c5c9aab6ce9e4d4998ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Oct 2026 17:34:06 +0000 Subject: [PATCH 01/48] build(deps): bump the rust-host group with 3 updates Bumps the rust-host group with 3 updates: [tree-sitter](https://github.com/tree-sitter/tree-sitter), [serde_json](https://github.com/serde-rs/json) and [toml](https://github.com/toml-rs/toml). Updates `tree-sitter` from 0.27.0 to 0.27.1 - [Release notes](https://github.com/tree-sitter/tree-sitter/releases) - [Commits](https://github.com/tree-sitter/tree-sitter/compare/v0.27.0...v0.27.1) Updates `serde_json` from 1.0.151 to 1.0.154 - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.151...v1.0.154) Updates `toml` from 1.1.6+spec-1.1.0 to 1.1.8+spec-1.1.0 - [Commits](https://github.com/toml-rs/toml/compare/toml-v1.1.6...toml-v1.1.8) --- updated-dependencies: - dependency-name: tree-sitter dependency-version: 0.27.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-host - dependency-name: serde_json dependency-version: 1.0.154 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-host - dependency-name: toml dependency-version: 1.1.8+spec-1.1.0 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-host ... Signed-off-by: dependabot[bot] --- Cargo.lock | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0c78abaa..06101877 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,6 +190,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -273,7 +279,7 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "foldhash", + "foldhash 0.1.5", ] [[package]] @@ -1088,10 +1094,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.151" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ + "foldhash 0.2.0", "indexmap", "itoa", "memchr", @@ -1113,9 +1120,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +checksum = "4e7523beb55eece201a2356bee0bbca0d1ab466c14c07703b2e0ee6d42cb0c2c" dependencies = [ "serde_core", ] @@ -1448,9 +1455,9 @@ dependencies = [ [[package]] name = "toml" -version = "1.1.6+spec-1.1.0" +version = "1.1.8+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "920602543f0911ab71da12c50d59701da54c196d1a2bf5cb4b75667f137a406a" +checksum = "20489e00e4d8741d6be680764cc12e270655e375a20d1011e844a9c3379e678d" dependencies = [ "indexmap", "serde_core", @@ -1463,27 +1470,27 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "1.1.1+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +checksum = "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053" dependencies = [ "serde_core", ] [[package]] name = "toml_parser" -version = "1.1.3+spec-1.1.0" +version = "1.1.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" dependencies = [ "winnow", ] [[package]] name = "toml_writer" -version = "1.1.2+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" +checksum = "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770" [[package]] name = "tower" @@ -1619,9 +1626,9 @@ dependencies = [ [[package]] name = "tree-sitter" -version = "0.27.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2038684e0058edba0d17302619f62eabce4a8e11c6ac59506996a8d79848851d" +checksum = "a5129de2ccc97808c4583d48f1fb44576d015cf241e432800572bda11ef30c3b" dependencies = [ "cc", "regex", @@ -1652,9 +1659,9 @@ dependencies = [ [[package]] name = "tree-sitter-language" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0d1bf6fdd806e43ae5198f82f527056d359def39e54e67a0f478ac09dac081" +checksum = "d0af592be68c579aa78a16846bd19422978c3c52e438523d45ff5d1bff1f9d4a" [[package]] name = "try-lock" From 511172185a8367d2404ef09e77226994058a2825 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Oct 2026 17:35:00 +0000 Subject: [PATCH 02/48] build(deps): bump toml in /src/editors/zed in the rust-zed group Bumps the rust-zed group in /src/editors/zed with 1 update: [toml](https://github.com/toml-rs/toml). Updates `toml` from 1.1.6+spec-1.1.0 to 1.1.8+spec-1.1.0 - [Commits](https://github.com/toml-rs/toml/compare/toml-v1.1.6...toml-v1.1.8) --- updated-dependencies: - dependency-name: toml dependency-version: 1.1.8+spec-1.1.0 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-zed ... Signed-off-by: dependabot[bot] --- src/editors/zed/Cargo.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/editors/zed/Cargo.lock b/src/editors/zed/Cargo.lock index 60b277e0..601932d8 100644 --- a/src/editors/zed/Cargo.lock +++ b/src/editors/zed/Cargo.lock @@ -477,9 +477,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +checksum = "4e7523beb55eece201a2356bee0bbca0d1ab466c14c07703b2e0ee6d42cb0c2c" dependencies = [ "serde_core", ] @@ -560,9 +560,9 @@ dependencies = [ [[package]] name = "toml" -version = "1.1.6+spec-1.1.0" +version = "1.1.8+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "920602543f0911ab71da12c50d59701da54c196d1a2bf5cb4b75667f137a406a" +checksum = "20489e00e4d8741d6be680764cc12e270655e375a20d1011e844a9c3379e678d" dependencies = [ "indexmap", "serde_core", @@ -575,27 +575,27 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "1.1.1+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +checksum = "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053" dependencies = [ "serde_core", ] [[package]] name = "toml_parser" -version = "1.1.3+spec-1.1.0" +version = "1.1.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" dependencies = [ "winnow", ] [[package]] name = "toml_writer" -version = "1.1.2+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" +checksum = "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770" [[package]] name = "topological-sort" From 70e2a3b5dd5d0513ac5a8cdb8856175ed42581f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Oct 2026 17:36:58 +0000 Subject: [PATCH 03/48] build(deps): bump the github-actions group with 6 updates Bumps the github-actions group with 6 updates: | Package | From | To | | --- | --- | --- | | [taiki-e/install-action](https://github.com/taiki-e/install-action) | `2.87.23` | `2.87.27` | | [actions/setup-node](https://github.com/actions/setup-node) | `7.0.0` | `7.1.0` | | [actions/download-artifact](https://github.com/actions/download-artifact) | `8.0.1` | `8.0.2` | | [actions/upload-artifact](https://github.com/actions/upload-artifact) | `7.0.1` | `7.0.2` | | [github/codeql-action/init](https://github.com/github/codeql-action) | `4.38.2` | `4.38.3` | | [github/codeql-action/analyze](https://github.com/github/codeql-action) | `4.38.2` | `4.38.3` | Updates `taiki-e/install-action` from 2.87.23 to 2.87.27 - [Release notes](https://github.com/taiki-e/install-action/releases) - [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/taiki-e/install-action/compare/861a07ce7084f55488e375df125cdc99bba60eb7...ab6895351a88b908e96a4697860d4ffea5e57dbe) Updates `actions/setup-node` from 7.0.0 to 7.1.0 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/820762786026740c76f36085b0efc47a31fe5020...949feb2413d6458794dcd2491c4babbbce0c15c1) Updates `actions/download-artifact` from 8.0.1 to 8.0.2 - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c...9000827ccba6bdab643e8b6fd33ac0654aef8333) Updates `actions/upload-artifact` from 7.0.1 to 7.0.2 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/043fb46d1a93c77aae656e7c1c64a875d1fc6a0a...cf430e030ddbb5b0abf93d22962f4752f3646cd9) Updates `github/codeql-action/init` from 4.38.2 to 4.38.3 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2...24c54180a607b1449ed407dd24f251e4e9147c8d) Updates `github/codeql-action/analyze` from 4.38.2 to 4.38.3 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2...24c54180a607b1449ed407dd24f251e4e9147c8d) --- updated-dependencies: - dependency-name: taiki-e/install-action dependency-version: 2.87.27 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/setup-node dependency-version: 7.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: actions/download-artifact dependency-version: 8.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/upload-artifact dependency-version: 7.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action/init dependency-version: 4.38.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action/analyze dependency-version: 4.38.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/ci-audit.yml | 4 ++-- .github/workflows/ci-build.yml | 2 +- .github/workflows/ci-coverage.yml | 12 +++++----- .github/workflows/ci-test-dotnet.yml | 2 +- .github/workflows/ci-test-editors.yml | 6 ++--- .github/workflows/ci-test-rust.yml | 14 +++++------ .github/workflows/ci-test-tooling.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/codeql.yml | 4 ++-- .github/workflows/deploy-pages.yml | 2 +- .github/workflows/release.yml | 34 +++++++++++++-------------- 11 files changed, 42 insertions(+), 42 deletions(-) diff --git a/.github/workflows/ci-audit.yml b/.github/workflows/ci-audit.yml index 7ac5c8a0..fb606e2f 100644 --- a/.github/workflows/ci-audit.yml +++ b/.github/workflows/ci-audit.yml @@ -36,13 +36,13 @@ jobs: - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: toolchain: stable - - uses: taiki-e/install-action@861a07ce7084f55488e375df125cdc99bba60eb7 # v2 + - uses: taiki-e/install-action@ab6895351a88b908e96a4697860d4ffea5e57dbe # v2 with: tool: cargo-audit - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: dotnet-version: 10.0.303 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' - name: Audit Rust, .NET and npm dependencies diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index fbfe6d65..083cefee 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -89,7 +89,7 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' - name: Download the pinned macOS debugger diff --git a/.github/workflows/ci-coverage.yml b/.github/workflows/ci-coverage.yml index aa0636c2..a8eb22fc 100644 --- a/.github/workflows/ci-coverage.yml +++ b/.github/workflows/ci-coverage.yml @@ -36,10 +36,10 @@ jobs: # check-coverage.mjs ratchets against the threshold committed at the # merge base, which a shallow checkout does not contain. fetch-depth: 0 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: pattern: coverage-rust-shard-* merge-multiple: true @@ -47,7 +47,7 @@ jobs: - name: Merge shard coverage and enforce threshold run: make _gate-rust-coverage - name: Upload merged coverage - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: coverage-rust path: | @@ -66,11 +66,11 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' - name: Download every shard tracefile (both platforms) - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: pattern: coverage-vsix-shard-* merge-multiple: true @@ -78,7 +78,7 @@ jobs: - name: Merge shard coverage and enforce threshold run: make _gate-vsix-coverage - name: Upload merged coverage - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: coverage-vsix path: | diff --git a/.github/workflows/ci-test-dotnet.yml b/.github/workflows/ci-test-dotnet.yml index 34f1b561..febb8218 100644 --- a/.github/workflows/ci-test-dotnet.yml +++ b/.github/workflows/ci-test-dotnet.yml @@ -33,7 +33,7 @@ jobs: 9.0.x 10.0.303 - name: Download prebuilt sidecars - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: linux-lsp-binaries path: target diff --git a/.github/workflows/ci-test-editors.yml b/.github/workflows/ci-test-editors.yml index 7fe0d6ed..d6abf5c8 100644 --- a/.github/workflows/ci-test-editors.yml +++ b/.github/workflows/ci-test-editors.yml @@ -43,10 +43,10 @@ jobs: - uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2 with: workspaces: src/editors/zed - - uses: taiki-e/install-action@861a07ce7084f55488e375df125cdc99bba60eb7 # v2 + - uses: taiki-e/install-action@ab6895351a88b908e96a4697860d4ffea5e57dbe # v2 with: tool: cargo-llvm-cov - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' - name: Test + coverage gate (Zed) @@ -67,7 +67,7 @@ jobs: with: distribution: temurin java-version: '21' - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' # kover-line-percent.cs is a `dotnet run --file` app, matching how diff --git a/.github/workflows/ci-test-rust.yml b/.github/workflows/ci-test-rust.yml index 37c741b8..1ddda8ec 100644 --- a/.github/workflows/ci-test-rust.yml +++ b/.github/workflows/ci-test-rust.yml @@ -40,10 +40,10 @@ jobs: toolchain: stable components: llvm-tools-preview - uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2 - - uses: taiki-e/install-action@861a07ce7084f55488e375df125cdc99bba60eb7 # v2 + - uses: taiki-e/install-action@ab6895351a88b908e96a4697860d4ffea5e57dbe # v2 with: tool: cargo-llvm-cov - - uses: taiki-e/install-action@861a07ce7084f55488e375df125cdc99bba60eb7 # v2 + - uses: taiki-e/install-action@ab6895351a88b908e96a4697860d4ffea5e57dbe # v2 with: tool: nextest - uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 @@ -58,7 +58,7 @@ jobs: ${{ runner.os }}-nuget-${{ hashFiles('src/sidecars/**/*.csproj', 'src/sidecars/Directory.Build.props') }} restore-keys: "${{ runner.os }}-nuget-" - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' - name: Install .NET diagnostic tools @@ -67,7 +67,7 @@ jobs: dotnet tool install -g dotnet-counters dotnet tool install -g dotnet-dump - name: Download prebuilt host and sidecars - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: linux-lsp-binaries path: target @@ -81,7 +81,7 @@ jobs: - name: Test Rust shard with coverage run: env VSIX_PREBUILT=1 make _test-rust-shard SHARD=${{ matrix.shard }} SHARD_COUNT=2 - name: Upload shard coverage - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: coverage-rust-shard-${{ matrix.shard }} retention-days: 1 @@ -105,11 +105,11 @@ jobs: - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable with: toolchain: stable - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' - name: Download prebuilt release binary - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: linux-lsp-binaries path: target diff --git a/.github/workflows/ci-test-tooling.yml b/.github/workflows/ci-test-tooling.yml index a62cb858..db845d5a 100644 --- a/.github/workflows/ci-test-tooling.yml +++ b/.github/workflows/ci-test-tooling.yml @@ -26,7 +26,7 @@ jobs: timeout-minutes: 10 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' - name: Test the build tooling diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3a680921..ef90356e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -155,7 +155,7 @@ jobs: # manifest changed. steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '24' - name: Validate shipwright.json diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5012db0b..dcf68b95 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -68,7 +68,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Initialize CodeQL - uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 + uses: github/codeql-action/init@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} @@ -76,7 +76,7 @@ jobs: # PR, weekly, and gated release scans stay identical. [DIST-CI-SECURITY] config-file: ./.github/codeql/codeql-config.yml - name: Perform CodeQL analysis - uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 + uses: github/codeql-action/analyze@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3 with: category: "/language:${{ matrix.language }}" # Drop the SARIF on disk so the gate step can read it. `upload` stays on diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml index c1abf179..077a2a08 100644 --- a/.github/workflows/deploy-pages.yml +++ b/.github/workflows/deploy-pages.yml @@ -39,7 +39,7 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: submodules: true - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' cache: npm diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8371ee1f..7786a2c1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,7 +28,7 @@ jobs: version: "${{ steps.extract.outputs.version }}" steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '24' - name: Extract version from tag @@ -126,7 +126,7 @@ jobs: dotnet-version: | 9.0.x 10.0.303 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' cache: npm @@ -182,14 +182,14 @@ jobs: export SKIP_RUN=1 fi bash tools/packaging/verify-archive.sh ${{ matrix.platform }} "${{ needs.version.outputs.version }}" - - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: vsix-${{ matrix.platform }} path: dist/*.vsix if-no-files-found: error # Uploaded separately from the VSIX so publish-marketplace / publish-openvsx # keep globbing a directory that holds nothing but .vsix files. - - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: server-${{ matrix.platform }} path: | @@ -219,7 +219,7 @@ jobs: with: distribution: temurin java-version: '21' - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' # Mirrors ci-test-editors.yml: the IntelliJ Platform SDK is a multi-GB Gradle @@ -246,7 +246,7 @@ jobs: # tag into it. A stale 0.1.0 here means stamping silently stopped working. ls src/editors/rider/build/distributions/sharplsp-rider-${{ needs.version.outputs.version }}.zip unzip -l dist/sharplsp-rider.zip | grep -F 'sharplsp-rider/lib/' - - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: rider-plugin path: dist/sharplsp-rider.zip @@ -268,17 +268,17 @@ jobs: # Three downloads, one directory. publish-marketplace and publish-openvsx # pull `vsix-*` on their own and must keep seeing a directory of nothing but # VSIXes, so the artifacts stay split at upload and are merged only here. - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: path: artifacts pattern: vsix-* merge-multiple: true - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: path: artifacts pattern: server-* merge-multiple: true - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: path: artifacts name: rider-plugin @@ -359,10 +359,10 @@ jobs: contents: read id-token: write steps: - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: path: artifacts pattern: vsix-* @@ -487,12 +487,12 @@ jobs: exit 1 fi - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' # Checksums come from the archives actually published, never from a # hand-edited formula — a carried-over sha256 is the classic tap bug. - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: path: artifacts pattern: server-* @@ -545,10 +545,10 @@ jobs: exit 1 fi - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: path: artifacts pattern: server-* @@ -589,10 +589,10 @@ jobs: permissions: contents: read steps: - - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '20' - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: path: artifacts pattern: vsix-* From 114737a0d7526a1a3c219465a9b988e383195ddf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Oct 2026 17:37:12 +0000 Subject: [PATCH 04/48] build(deps): bump @playwright/test in /src/website in the website group Bumps the website group in /src/website with 1 update: [@playwright/test](https://github.com/microsoft/playwright). Updates `@playwright/test` from 1.63.0 to 1.64.0 - [Release notes](https://github.com/microsoft/playwright/releases) - [Commits](https://github.com/microsoft/playwright/compare/v1.63.0...v1.64.0) --- updated-dependencies: - dependency-name: "@playwright/test" dependency-version: 1.64.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: website ... Signed-off-by: dependabot[bot] --- src/website/package-lock.json | 24 ++++++++++++------------ src/website/package.json | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/website/package-lock.json b/src/website/package-lock.json index 9fd6b511..4d4809e2 100644 --- a/src/website/package-lock.json +++ b/src/website/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "dependencies": { "@11ty/eleventy": "^3.1.6", - "@playwright/test": "^1.63.0", + "@playwright/test": "^1.64.0", "eleventy-plugin-techdoc": "0.2.0", "markdown-it": "^15.0.2" }, @@ -628,12 +628,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.63.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.63.0.tgz", - "integrity": "sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==", + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.64.0.tgz", + "integrity": "sha512-oTN9FNYuN6bqQMwiho6jJKLCG2/QOYCixGXuCjRmzOq23eODeukuY2XiAVoVpAECbuezMt1MHQjAiQxK8F+Y+g==", "license": "Apache-2.0", "dependencies": { - "playwright": "1.63.0" + "playwright": "1.64.0" }, "bin": { "playwright": "cli.js" @@ -1757,12 +1757,12 @@ } }, "node_modules/playwright": { - "version": "1.63.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz", - "integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==", + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.64.0.tgz", + "integrity": "sha512-kVzTnYFYEyQ9RGzBjNCd2+yEqWmVbxl3AHPynv3qQ6JTjv4a+kwRcnqQwIpuP3NnrnIrE/Q6wWAIAvMfIE2/Yg==", "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.63.0" + "playwright-core": "1.64.0" }, "bin": { "playwright": "cli.js" @@ -1772,9 +1772,9 @@ } }, "node_modules/playwright-core": { - "version": "1.63.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz", - "integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==", + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.64.0.tgz", + "integrity": "sha512-T9r+MZkTECl2+oUcZ26YgZzTrYidTsIhYYkJix+6iDOymOb1FB2RLLSOxRGnZGv5DStt+aduIVbt+E8WygXYpg==", "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" diff --git a/src/website/package.json b/src/website/package.json index 346b7265..d067aa1a 100644 --- a/src/website/package.json +++ b/src/website/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@11ty/eleventy": "^3.1.6", - "@playwright/test": "^1.63.0", + "@playwright/test": "^1.64.0", "eleventy-plugin-techdoc": "0.2.0", "markdown-it": "^15.0.2" }, From c42ca8325d8375bec293e009b009f365f52e609c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Oct 2026 17:38:33 +0000 Subject: [PATCH 05/48] build(deps-dev): bump the vscode-extension group Bumps the vscode-extension group in /src/editors/vscode with 7 updates: | Package | From | To | | --- | --- | --- | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.6.4` | `26.6.5` | | [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `8.71.0` | `8.71.1` | | [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `8.71.0` | `8.71.1` | | [playwright](https://github.com/microsoft/playwright) | `1.63.0` | `1.64.0` | | [prettier](https://github.com/prettier/prettier) | `3.9.9` | `3.9.10` | | [typescript](https://github.com/microsoft/TypeScript) | `6.0.3` | `7.0.2` | | [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.71.0` | `8.71.1` | Updates `@types/node` from 26.6.4 to 26.6.5 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Updates `@typescript-eslint/eslint-plugin` from 8.71.0 to 8.71.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.71.1/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 8.71.0 to 8.71.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.71.1/packages/parser) Updates `playwright` from 1.63.0 to 1.64.0 - [Release notes](https://github.com/microsoft/playwright/releases) - [Commits](https://github.com/microsoft/playwright/compare/v1.63.0...v1.64.0) Updates `prettier` from 3.9.9 to 3.9.10 - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/3.9.9...3.9.10) Updates `typescript` from 6.0.3 to 7.0.2 - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Commits](https://github.com/microsoft/TypeScript/compare/v6.0.3...v7.0.2) Updates `typescript-eslint` from 8.71.0 to 8.71.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.71.1/packages/typescript-eslint) --- updated-dependencies: - dependency-name: "@types/node" dependency-version: 26.6.5 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vscode-extension - dependency-name: "@typescript-eslint/eslint-plugin" dependency-version: 8.71.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vscode-extension - dependency-name: "@typescript-eslint/parser" dependency-version: 8.71.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vscode-extension - dependency-name: playwright dependency-version: 1.64.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: vscode-extension - dependency-name: prettier dependency-version: 3.9.10 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vscode-extension - dependency-name: typescript dependency-version: 7.0.2 dependency-type: direct:development update-type: version-update:semver-major dependency-group: vscode-extension - dependency-name: typescript-eslint dependency-version: 8.71.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vscode-extension ... Signed-off-by: dependabot[bot] --- src/editors/vscode/package-lock.json | 714 +++++++++++++++++++++------ src/editors/vscode/package.json | 14 +- 2 files changed, 578 insertions(+), 150 deletions(-) diff --git a/src/editors/vscode/package-lock.json b/src/editors/vscode/package-lock.json index 8824fed3..3585a6e7 100644 --- a/src/editors/vscode/package-lock.json +++ b/src/editors/vscode/package-lock.json @@ -18,10 +18,10 @@ "@eslint/js": "^10.0.1", "@types/d3-force": "^3.0.10", "@types/mocha": "^10.0.6", - "@types/node": "^26.6.4", + "@types/node": "^26.6.5", "@types/vscode": "^1.105.0", - "@typescript-eslint/eslint-plugin": "^8.71.0", - "@typescript-eslint/parser": "^8.71.0", + "@typescript-eslint/eslint-plugin": "^8.71.1", + "@typescript-eslint/parser": "^8.71.1", "@vscode/test-cli": "^0.0.15", "@vscode/test-electron": "^3.1.0", "@vscode/vsce": "^4.0.0", @@ -29,10 +29,10 @@ "eslint": "^10.12.0", "glob": "^13.0.6", "mocha": "^12.0.3", - "playwright": "^1.63.0", - "prettier": "3.9.9", - "typescript": "~6.0.3", - "typescript-eslint": "^8.71.0" + "playwright": "^1.64.0", + "prettier": "3.9.10", + "typescript": "~7.0.2", + "typescript-eslint": "^8.71.1" }, "engines": { "vscode": "^1.105.0" @@ -1328,9 +1328,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "26.6.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.4.tgz", - "integrity": "sha512-ldVPDCzj7fsaGZrLB0NuHuTvJcsNasysBAqMolr/cgxrLd1xbqxIr3XJiPnHHJUCxj5sNF1vnRj9aWnrVh5Jcg==", + "version": "26.6.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.5.tgz", + "integrity": "sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==", "dev": true, "license": "MIT", "dependencies": { @@ -1345,17 +1345,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.71.0.tgz", - "integrity": "sha512-pqcS9c1HxZTHt7End4nXqd0s5lJrrFzrgCkKFJrsbUnaL6M3+6oBFZaslg6Gjsl3argl2DDRFROnXARaZ2e4Nw==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.71.1.tgz", + "integrity": "sha512-nNlBf6HuotqMgZvSkWD5hNdemiBIxQ2NmrlgfcUIeZRs+BbakjscCQRq/Hb74EFVnFiSWWdL12JruqwBy3ERDw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.71.0", - "@typescript-eslint/type-utils": "8.71.0", - "@typescript-eslint/utils": "8.71.0", - "@typescript-eslint/visitor-keys": "8.71.0", + "@typescript-eslint/scope-manager": "8.71.1", + "@typescript-eslint/type-utils": "8.71.1", + "@typescript-eslint/utils": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -1368,21 +1368,23 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.71.0", + "@typescript-eslint/parser": "^8.71.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/project-service": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.0.tgz", - "integrity": "sha512-aABjw5rjBacYONVPaPiWOCjJu0vEF4a25iQuodlmQYL1trtLZ0X/y+2Vzl3BKI1odM4LnwLE1oUDXYp1wzx1TQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.71.1.tgz", + "integrity": "sha512-kH3t3jZCYv2PZSBEWPKTariLrCaoF1CLoPitYFBJOhAGEwWnSRAtGEifrfrpBa4K9JlwWNZotgA5w3/wLSk/FQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.71.0", - "@typescript-eslint/types": "^8.71.0", - "debug": "^4.4.3" + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/typescript-estree": "8.71.1", + "@typescript-eslint/utils": "8.71.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1392,15 +1394,27 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.0.tgz", - "integrity": "sha512-Z1UlWHADEK2Mlb9NpWfDeSjqoZ5EyrOv4R3eQpbkzqn/EwaIdOpXXupEA1+0ZIOSJSZZDBHG0BrQyN8zUG6Pwg==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.1.tgz", + "integrity": "sha512-pSKSEK1JJpHs6KiKVtABCE4iJK5d7FLFzDXQNBQ2oRY7LEd3UwOt3TZemTgu9syTIf56dJWlTn/pdmrO9oKUXQ==", "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.71.1", + "@typescript-eslint/tsconfig-utils": "8.71.1", + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1412,18 +1426,16 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.71.0.tgz", - "integrity": "sha512-i8uO1qbdxeKgRnS5sCRt6On3/nfo2d2DwQe3Yvjx543zLy7r8ySqRuPPiIIXAhS03U0v5NfAFx+rUgxFzKKwNw==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.1.tgz", + "integrity": "sha512-Oijc9RUsohHjncg6iGi7gCtjnEjYt9FWv9u6ygK8uKcHK5eLjLAkqERQ9BaytbpceOFdk6kifPCS/zAZE+A99g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.71.0", - "@typescript-eslint/typescript-estree": "8.71.0", - "@typescript-eslint/utils": "8.71.0", - "debug": "^4.4.3", - "ts-api-utils": "^2.5.0" + "@typescript-eslint/tsconfig-utils": "^8.71.1", + "@typescript-eslint/types": "^8.71.1", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1433,27 +1445,15 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.0.tgz", - "integrity": "sha512-PEEF4G5sLLWAS5BpPrUvms4ySZkiBQQZM4z+3ReI46axK5Vqr/vXBQatJQIZZOYdGyPUAKTtsrWzpqKuU+3DEw==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.1.tgz", + "integrity": "sha512-oTvkml5SxXhgg+WWKhod5qWQICDXtOB+/Hi9VdPKFAANJ2b7YOgMffgvzXuqog7R6A/JtrzRf128dsxummyWhg==", "dev": true, "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.71.0", - "@typescript-eslint/tsconfig-utils": "8.71.0", - "@typescript-eslint/types": "8.71.0", - "@typescript-eslint/visitor-keys": "8.71.0", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.5.0" - }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1466,16 +1466,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.71.0.tgz", - "integrity": "sha512-pKR/tEMVrXZG23UFKUn5BQf3zfmfk7KQceI2cGzywZ5nxM5Eu3hEJU1utjWzydtzBbcJAQhHN8iPCxobHpPcZQ==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.71.1.tgz", + "integrity": "sha512-CBjT6gfAz3DW2j9Q4moFnqt208Aq+506sVGXfpRcyAeqn0EpayL0mjdWoCO2t3RC7GewNrFxdeehuEaPg6DMzQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.71.0", - "@typescript-eslint/types": "8.71.0", - "@typescript-eslint/typescript-estree": "8.71.0" + "@typescript-eslint/scope-manager": "8.71.1", + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/typescript-estree": "8.71.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1489,18 +1489,22 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/parser": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.71.0.tgz", - "integrity": "sha512-CG4nPk1f2zc8yw4pALqHsFYH2hdo+h1T9daSp21+Hnxi9LOE3GT9hAfTKJCBXVNM2GmYs1eMEP615wPoeOgk3A==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.1.tgz", + "integrity": "sha512-pSKSEK1JJpHs6KiKVtABCE4iJK5d7FLFzDXQNBQ2oRY7LEd3UwOt3TZemTgu9syTIf56dJWlTn/pdmrO9oKUXQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.71.0", - "@typescript-eslint/types": "8.71.0", - "@typescript-eslint/typescript-estree": "8.71.0", - "@typescript-eslint/visitor-keys": "8.71.0", - "debug": "^4.4.3" + "@typescript-eslint/project-service": "8.71.1", + "@typescript-eslint/tsconfig-utils": "8.71.1", + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1510,19 +1514,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/project-service": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.0.tgz", - "integrity": "sha512-aABjw5rjBacYONVPaPiWOCjJu0vEF4a25iQuodlmQYL1trtLZ0X/y+2Vzl3BKI1odM4LnwLE1oUDXYp1wzx1TQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.1.tgz", + "integrity": "sha512-Oijc9RUsohHjncg6iGi7gCtjnEjYt9FWv9u6ygK8uKcHK5eLjLAkqERQ9BaytbpceOFdk6kifPCS/zAZE+A99g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.71.0", - "@typescript-eslint/types": "^8.71.0", + "@typescript-eslint/tsconfig-utils": "^8.71.1", + "@typescript-eslint/types": "^8.71.1", "debug": "^4.4.3" }, "engines": { @@ -1536,12 +1539,36 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.0.tgz", - "integrity": "sha512-Z1UlWHADEK2Mlb9NpWfDeSjqoZ5EyrOv4R3eQpbkzqn/EwaIdOpXXupEA1+0ZIOSJSZZDBHG0BrQyN8zUG6Pwg==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.1.tgz", + "integrity": "sha512-oTvkml5SxXhgg+WWKhod5qWQICDXtOB+/Hi9VdPKFAANJ2b7YOgMffgvzXuqog7R6A/JtrzRf128dsxummyWhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.71.1.tgz", + "integrity": "sha512-oM/5sAqz/l1v/zYK1qTOPrn2+JIrBGC1V6uNYucRO5gh6eT9vWJ/RhPbGE59byvZEUQ4VP6XkLBaS5Jti5jpvw==", "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.71.1", + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/typescript-estree": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1", + "debug": "^4.4.3" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -1550,20 +1577,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.0.tgz", - "integrity": "sha512-PEEF4G5sLLWAS5BpPrUvms4ySZkiBQQZM4z+3ReI46axK5Vqr/vXBQatJQIZZOYdGyPUAKTtsrWzpqKuU+3DEw==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.1.tgz", + "integrity": "sha512-pSKSEK1JJpHs6KiKVtABCE4iJK5d7FLFzDXQNBQ2oRY7LEd3UwOt3TZemTgu9syTIf56dJWlTn/pdmrO9oKUXQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.71.0", - "@typescript-eslint/tsconfig-utils": "8.71.0", - "@typescript-eslint/types": "8.71.0", - "@typescript-eslint/visitor-keys": "8.71.0", + "@typescript-eslint/project-service": "8.71.1", + "@typescript-eslint/tsconfig-utils": "8.71.1", + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -1581,15 +1609,54 @@ "typescript": ">=4.8.4 <6.1.0" } }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.1.tgz", + "integrity": "sha512-Oijc9RUsohHjncg6iGi7gCtjnEjYt9FWv9u6ygK8uKcHK5eLjLAkqERQ9BaytbpceOFdk6kifPCS/zAZE+A99g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.71.1", + "@typescript-eslint/types": "^8.71.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.1.tgz", + "integrity": "sha512-oTvkml5SxXhgg+WWKhod5qWQICDXtOB+/Hi9VdPKFAANJ2b7YOgMffgvzXuqog7R6A/JtrzRf128dsxummyWhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.71.0.tgz", - "integrity": "sha512-gWF0BhUcnjZxSpLE8ngS/59n2SB0J3YqRxvX1+2aoRJk9hNtHSLOV+TcarFiOr5ipXm3yc1QrI4c9YZc8zyCxw==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.71.1.tgz", + "integrity": "sha512-1YUDZXdTnXLlob03SFHBipdyMBsDVm7zoSz0ytTJ39dk5J1TgsTK03VlR/dLXG/RLLUrPcYbD4rp23BmHxHP0w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.71.0", - "@typescript-eslint/visitor-keys": "8.71.0" + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1600,9 +1667,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.71.0.tgz", - "integrity": "sha512-cJ4OoxPGWvFnBTnSZyaU+qJzGTqPTGJY+gDchj6cRyLRdmIdt4rcsE4twj+zPfrNiWuVi38wijHzShL++Z9atQ==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.71.1.tgz", + "integrity": "sha512-ybYnPTUwg3VQQOFEiBPLs8Jxl1ry2vXdn1kVKguomBbvxpetdu3MKTNDqFNUrlG8ylP9MpZosmXMFYlGQHk1oQ==", "dev": true, "license": "MIT", "engines": { @@ -1614,13 +1681,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.71.0.tgz", - "integrity": "sha512-8eQ9R218XORK+KLosnf4bu/QsUXvUyVwTbArg7/0NMB1Pu87OJKvj4nhFblkYE8gQV73mW1dx1ptlPCkwRGa7A==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.71.1.tgz", + "integrity": "sha512-0GxiUGqMU0qXJt58cBsiG3DP8lUmBaFo2vChtUX+CT7PnR3v/VGLLrzVP4K9r1lNiZXjHYefMBbPunplr09v6w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.71.0", + "@typescript-eslint/types": "8.71.1", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -1644,6 +1711,346 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/@typespec/ts-http-runtime": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.9.tgz", @@ -4176,13 +4583,13 @@ } }, "node_modules/playwright": { - "version": "1.63.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz", - "integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==", + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.64.0.tgz", + "integrity": "sha512-kVzTnYFYEyQ9RGzBjNCd2+yEqWmVbxl3AHPynv3qQ6JTjv4a+kwRcnqQwIpuP3NnrnIrE/Q6wWAIAvMfIE2/Yg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.63.0" + "playwright-core": "1.64.0" }, "bin": { "playwright": "cli.js" @@ -4192,9 +4599,9 @@ } }, "node_modules/playwright-core": { - "version": "1.63.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz", - "integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==", + "version": "1.64.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.64.0.tgz", + "integrity": "sha512-T9r+MZkTECl2+oUcZ26YgZzTrYidTsIhYYkJix+6iDOymOb1FB2RLLSOxRGnZGv5DStt+aduIVbt+E8WygXYpg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4215,9 +4622,9 @@ } }, "node_modules/prettier": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.9.tgz", - "integrity": "sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg==", + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.10.tgz", + "integrity": "sha512-skGHTH1Yb9QvaTC4hWnRTzEYtCpApF0UMBPz+t/0ZPzP8ihefo/btKd+QA7pUE0fEwA1SbS/NmhyEcstdXOIdA==", "dev": true, "license": "MIT", "bin": { @@ -4808,30 +5215,51 @@ } }, "node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", "dev": true, "license": "Apache-2.0", "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "tsc": "bin/tsc" }, "engines": { - "node": ">=14.17" + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" } }, "node_modules/typescript-eslint": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.71.0.tgz", - "integrity": "sha512-fBdHYiqQ14RW6mOMXD14Svn82ZsCYAoQSzGRzyEjR59S5A2Krh/l7fGTOQ7iCr8gGy/mHVXtEF7s5fgjEdV0Pw==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.71.1.tgz", + "integrity": "sha512-oiNVPC3/NbV1FpaHU07l8O6ynqG9v4PAiW2WvTrAmZdR0f2HI/gE668ElMLCK7Xbsu5k2fK5C4fXNiq05j7/nQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.71.0", - "@typescript-eslint/parser": "8.71.0", - "@typescript-eslint/typescript-estree": "8.71.0", - "@typescript-eslint/utils": "8.71.0" + "@typescript-eslint/eslint-plugin": "8.71.1", + "@typescript-eslint/parser": "8.71.1", + "@typescript-eslint/typescript-estree": "8.71.1", + "@typescript-eslint/utils": "8.71.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4846,16 +5274,16 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.0.tgz", - "integrity": "sha512-PEEF4G5sLLWAS5BpPrUvms4ySZkiBQQZM4z+3ReI46axK5Vqr/vXBQatJQIZZOYdGyPUAKTtsrWzpqKuU+3DEw==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.1.tgz", + "integrity": "sha512-pSKSEK1JJpHs6KiKVtABCE4iJK5d7FLFzDXQNBQ2oRY7LEd3UwOt3TZemTgu9syTIf56dJWlTn/pdmrO9oKUXQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.71.0", - "@typescript-eslint/tsconfig-utils": "8.71.0", - "@typescript-eslint/types": "8.71.0", - "@typescript-eslint/visitor-keys": "8.71.0", + "@typescript-eslint/project-service": "8.71.1", + "@typescript-eslint/tsconfig-utils": "8.71.1", + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/visitor-keys": "8.71.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -4874,14 +5302,14 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.0.tgz", - "integrity": "sha512-aABjw5rjBacYONVPaPiWOCjJu0vEF4a25iQuodlmQYL1trtLZ0X/y+2Vzl3BKI1odM4LnwLE1oUDXYp1wzx1TQ==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.1.tgz", + "integrity": "sha512-Oijc9RUsohHjncg6iGi7gCtjnEjYt9FWv9u6ygK8uKcHK5eLjLAkqERQ9BaytbpceOFdk6kifPCS/zAZE+A99g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.71.0", - "@typescript-eslint/types": "^8.71.0", + "@typescript-eslint/tsconfig-utils": "^8.71.1", + "@typescript-eslint/types": "^8.71.1", "debug": "^4.4.3" }, "engines": { @@ -4896,9 +5324,9 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.0.tgz", - "integrity": "sha512-Z1UlWHADEK2Mlb9NpWfDeSjqoZ5EyrOv4R3eQpbkzqn/EwaIdOpXXupEA1+0ZIOSJSZZDBHG0BrQyN8zUG6Pwg==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.1.tgz", + "integrity": "sha512-oTvkml5SxXhgg+WWKhod5qWQICDXtOB+/Hi9VdPKFAANJ2b7YOgMffgvzXuqog7R6A/JtrzRf128dsxummyWhg==", "dev": true, "license": "MIT", "engines": { @@ -4913,16 +5341,16 @@ } }, "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "8.71.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.71.0.tgz", - "integrity": "sha512-pKR/tEMVrXZG23UFKUn5BQf3zfmfk7KQceI2cGzywZ5nxM5Eu3hEJU1utjWzydtzBbcJAQhHN8iPCxobHpPcZQ==", + "version": "8.71.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.71.1.tgz", + "integrity": "sha512-CBjT6gfAz3DW2j9Q4moFnqt208Aq+506sVGXfpRcyAeqn0EpayL0mjdWoCO2t3RC7GewNrFxdeehuEaPg6DMzQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.71.0", - "@typescript-eslint/types": "8.71.0", - "@typescript-eslint/typescript-estree": "8.71.0" + "@typescript-eslint/scope-manager": "8.71.1", + "@typescript-eslint/types": "8.71.1", + "@typescript-eslint/typescript-estree": "8.71.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/src/editors/vscode/package.json b/src/editors/vscode/package.json index 74148da5..1850534f 100644 --- a/src/editors/vscode/package.json +++ b/src/editors/vscode/package.json @@ -1272,10 +1272,10 @@ "@eslint/js": "^10.0.1", "@types/d3-force": "^3.0.10", "@types/mocha": "^10.0.6", - "@types/node": "^26.6.4", + "@types/node": "^26.6.5", "@types/vscode": "^1.105.0", - "@typescript-eslint/eslint-plugin": "^8.71.0", - "@typescript-eslint/parser": "^8.71.0", + "@typescript-eslint/eslint-plugin": "^8.71.1", + "@typescript-eslint/parser": "^8.71.1", "@vscode/test-cli": "^0.0.15", "@vscode/test-electron": "^3.1.0", "@vscode/vsce": "^4.0.0", @@ -1283,10 +1283,10 @@ "eslint": "^10.12.0", "glob": "^13.0.6", "mocha": "^12.0.3", - "playwright": "^1.63.0", - "prettier": "3.9.9", - "typescript": "~6.0.3", - "typescript-eslint": "^8.71.0" + "playwright": "^1.64.0", + "prettier": "3.9.10", + "typescript": "~7.0.2", + "typescript-eslint": "^8.71.1" }, "files": [ "bin/", From 92573de2a877317451ee47a0ca07cb215eafa53a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Oct 2026 17:41:52 +0000 Subject: [PATCH 06/48] Bump the dotnet-sidecars group with 8 updates Bumps Fantomas.Core from 8.0.7 to 8.0.8 Bumps FSharp.Compiler.Service from 43.12.401 to 43.12.402 Bumps FSharp.Core from 10.1.401 to 10.1.402 Bumps MessagePack from 3.1.11 to 3.1.12 Bumps Microsoft.CodeAnalysis.NetAnalyzers from 10.0.401 to 10.0.402 Bumps Microsoft.NET.Test.Sdk from 18.10.1 to 18.11.0 Bumps System.Security.Cryptography.Xml from 10.0.12 to 10.0.13 Bumps xunit.runner.visualstudio from 4.0.0 to 4.0.1 --- updated-dependencies: - dependency-name: Fantomas.Core dependency-version: 8.0.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dotnet-sidecars - dependency-name: FSharp.Compiler.Service dependency-version: 43.12.402 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dotnet-sidecars - dependency-name: FSharp.Core dependency-version: 10.1.402 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dotnet-sidecars - dependency-name: FSharp.Core dependency-version: 10.1.402 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dotnet-sidecars - dependency-name: MessagePack dependency-version: 3.1.12 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dotnet-sidecars - dependency-name: MessagePack dependency-version: 3.1.12 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dotnet-sidecars - dependency-name: Microsoft.CodeAnalysis.NetAnalyzers dependency-version: 10.0.402 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dotnet-sidecars - dependency-name: Microsoft.NET.Test.Sdk dependency-version: 18.11.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dotnet-sidecars - dependency-name: Microsoft.NET.Test.Sdk dependency-version: 18.11.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dotnet-sidecars - dependency-name: System.Security.Cryptography.Xml dependency-version: 10.0.13 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dotnet-sidecars - dependency-name: xunit.runner.visualstudio dependency-version: 4.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dotnet-sidecars - dependency-name: xunit.runner.visualstudio dependency-version: 4.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: dotnet-sidecars ... Signed-off-by: dependabot[bot] --- .config/dotnet/common.props | 2 +- .../SharpLsp.Sidecar.Common.Tests.csproj | 4 ++-- .../SharpLsp.Sidecar.Common.csproj | 2 +- .../SharpLsp.Sidecar.FSharp.Tests.fsproj | 8 ++++---- .../SharpLsp.Sidecar.FSharp.fsproj | 10 +++++----- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.config/dotnet/common.props b/.config/dotnet/common.props index 51399b9e..90939ca4 100644 --- a/.config/dotnet/common.props +++ b/.config/dotnet/common.props @@ -29,7 +29,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/src/sidecars/SharpLsp.Sidecar.Common.Tests/SharpLsp.Sidecar.Common.Tests.csproj b/src/sidecars/SharpLsp.Sidecar.Common.Tests/SharpLsp.Sidecar.Common.Tests.csproj index 08a44fa0..cbd6c217 100644 --- a/src/sidecars/SharpLsp.Sidecar.Common.Tests/SharpLsp.Sidecar.Common.Tests.csproj +++ b/src/sidecars/SharpLsp.Sidecar.Common.Tests/SharpLsp.Sidecar.Common.Tests.csproj @@ -14,9 +14,9 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + - + diff --git a/src/sidecars/SharpLsp.Sidecar.Common/SharpLsp.Sidecar.Common.csproj b/src/sidecars/SharpLsp.Sidecar.Common/SharpLsp.Sidecar.Common.csproj index 21548672..ed9ed165 100644 --- a/src/sidecars/SharpLsp.Sidecar.Common/SharpLsp.Sidecar.Common.csproj +++ b/src/sidecars/SharpLsp.Sidecar.Common/SharpLsp.Sidecar.Common.csproj @@ -23,7 +23,7 @@ - + diff --git a/src/sidecars/SharpLsp.Sidecar.FSharp.Tests/SharpLsp.Sidecar.FSharp.Tests.fsproj b/src/sidecars/SharpLsp.Sidecar.FSharp.Tests/SharpLsp.Sidecar.FSharp.Tests.fsproj index faf47b24..66809513 100644 --- a/src/sidecars/SharpLsp.Sidecar.FSharp.Tests/SharpLsp.Sidecar.FSharp.Tests.fsproj +++ b/src/sidecars/SharpLsp.Sidecar.FSharp.Tests/SharpLsp.Sidecar.FSharp.Tests.fsproj @@ -40,11 +40,11 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - - + + + - + diff --git a/src/sidecars/SharpLsp.Sidecar.FSharp/SharpLsp.Sidecar.FSharp.fsproj b/src/sidecars/SharpLsp.Sidecar.FSharp/SharpLsp.Sidecar.FSharp.fsproj index 944d7f00..f8962846 100644 --- a/src/sidecars/SharpLsp.Sidecar.FSharp/SharpLsp.Sidecar.FSharp.fsproj +++ b/src/sidecars/SharpLsp.Sidecar.FSharp/SharpLsp.Sidecar.FSharp.fsproj @@ -31,17 +31,17 @@ - - + + - + - + - + From daad1eb246487d9f0585d38288706e6974e6dcee Mon Sep 17 00:00:00 2001 From: Christian Findlay <16697547+MelbourneDeveloper@users.noreply.github.com> Date: Tue, 20 Oct 2026 18:14:20 +1100 Subject: [PATCH 07/48] Videos: one folder for every film, still and hero profiler-film/ held every video on the site, not just the profiler's. It is now src/website/tools/video/, and the blog hero page moves into video/heroes/. The frame-stepping renderer the profiler film used is now kit/frames.mjs, so every composited film renders through the same code. AGENTS.md: large files go in Git LFS; commit and push after each major change. --- AGENTS.md | 7 +- Makefile | 6 +- docs/specs/DESIGN-SYSTEM.md | 2 +- src/website/tests/profiler-media.spec.js | 2 +- .../profiler-film/films/profiler/render.mjs | 107 ------------------ .../tools/{profiler-film => video}/.gitignore | 0 .../tools/{profiler-film => video}/README.md | 13 ++- .../{profiler-film => video}/demos/Shop.slnx | 0 .../blazor-storefront/BlazorStorefront.csproj | 0 .../blazor-storefront/BlazorStorefront.slnx | 0 .../demos/blazor-storefront/Catalog.cs | 0 .../blazor-storefront/Components/App.razor | 0 .../Components/Layout/MainLayout.razor | 0 .../Components/Pages/Basket.razor | 0 .../blazor-storefront/Components/Routes.razor | 0 .../Components/_Imports.razor | 0 .../blazor-storefront/Directory.Build.props | 0 .../demos/blazor-storefront/Program.cs | 0 .../demos/fs-storefront/Catalog.fs | 0 .../demos/fs-storefront/Checkout.fs | 0 .../demos/fs-storefront/Directory.Build.props | 0 .../demos/fs-storefront/Domain.fs | 0 .../demos/fs-storefront/FsStorefront.fsproj | 0 .../demos/fs-storefront/FsStorefront.slnx | 0 .../demos/fs-storefront/Program.fs | 0 .../demos/fs-storefront/Sessions.fs | 0 .../demos/storefront/Catalog.cs | 0 .../demos/storefront/CheckoutPipeline.cs | 0 .../demos/storefront/Directory.Build.props | 0 .../demos/storefront/Program.cs | 0 .../demos/storefront/SessionCache.cs | 0 .../demos/storefront/Storefront.csproj | 0 .../demos/storefront/Storefront.slnx | 0 .../tools/{profiler-film => video}/film.mjs | 4 +- .../films/architecture.mjs | 2 +- .../films/architecture.narration.json | 0 .../{profiler-film => video}/films/blazor.mjs | 2 +- .../films/blazor.narration.json | 0 .../films/completions.mjs | 2 +- .../films/completions.narration.json | 0 .../films/configuration.mjs | 2 +- .../films/configuration.narration.json | 0 .../films/context-menus.mjs | 2 +- .../films/context-menus.narration.json | 0 .../films/contributing.mjs | 2 +- .../films/contributing.narration.json | 0 .../{profiler-film => video}/films/csharp.mjs | 2 +- .../films/csharp.narration.json | 0 .../films/diagnostics.mjs | 2 +- .../films/diagnostics.narration.json | 0 .../films/doc-stills.mjs | 2 +- .../films/editor-setup.mjs | 2 +- .../films/editor-setup.narration.json | 0 .../films/fsharp-language.mjs | 2 +- .../films/fsharp-language.narration.json | 0 .../{profiler-film => video}/films/fsharp.mjs | 2 +- .../films/fsharp.narration.json | 0 .../films/getting-started.mjs | 2 +- .../films/getting-started.narration.json | 0 .../{profiler-film => video}/films/hover.mjs | 2 +- .../films/hover.narration.json | 0 .../{profiler-film => video}/films/leak.mjs | 2 +- .../films/leak.narration.json | 0 .../films/navigation.mjs | 2 +- .../films/navigation.narration.json | 0 .../{profiler-film => video}/films/nuget.mjs | 2 +- .../films/nuget.narration.json | 0 .../films/profiler/capture.mjs | 4 +- .../films/profiler/film.html | 0 .../films/profiler/film.js | 0 .../films/profiler/flamegraph.mjs | 0 .../tools/video/films/profiler/render.mjs | 59 ++++++++++ .../films/refactoring.mjs | 2 +- .../films/refactoring.narration.json | 0 .../heroes/netfx-windows.html} | 0 .../{profiler-film => video}/kit/acts/cpu.mjs | 0 .../kit/acts/explorer.mjs | 0 .../kit/acts/language.mjs | 0 .../kit/acts/memory.mjs | 0 .../kit/acts/shop.mjs | 0 .../kit/acts/tour.mjs | 0 .../{profiler-film => video}/kit/camera.mjs | 0 .../{profiler-film => video}/kit/code.mjs | 0 .../{profiler-film => video}/kit/editor.mjs | 0 .../{profiler-film => video}/kit/encode.mjs | 0 src/website/tools/video/kit/frames.mjs | 80 +++++++++++++ .../{profiler-film => video}/kit/overlay.mjs | 0 .../{profiler-film => video}/kit/scenes.mjs | 0 .../kit/screencast.mjs | 0 .../{profiler-film => video}/kit/set.mjs | 0 .../kit/sound/score.mjs | 0 .../kit/sound/soundtrack.mjs | 0 .../kit/sound/voice.mjs | 0 .../kit/workbench.mjs | 0 .../package-lock.json | 4 +- .../{profiler-film => video}/package.json | 2 +- 96 files changed, 183 insertions(+), 143 deletions(-) delete mode 100644 src/website/tools/profiler-film/films/profiler/render.mjs rename src/website/tools/{profiler-film => video}/.gitignore (100%) rename src/website/tools/{profiler-film => video}/README.md (87%) rename src/website/tools/{profiler-film => video}/demos/Shop.slnx (100%) rename src/website/tools/{profiler-film => video}/demos/blazor-storefront/BlazorStorefront.csproj (100%) rename src/website/tools/{profiler-film => video}/demos/blazor-storefront/BlazorStorefront.slnx (100%) rename src/website/tools/{profiler-film => video}/demos/blazor-storefront/Catalog.cs (100%) rename src/website/tools/{profiler-film => video}/demos/blazor-storefront/Components/App.razor (100%) rename src/website/tools/{profiler-film => video}/demos/blazor-storefront/Components/Layout/MainLayout.razor (100%) rename src/website/tools/{profiler-film => video}/demos/blazor-storefront/Components/Pages/Basket.razor (100%) rename src/website/tools/{profiler-film => video}/demos/blazor-storefront/Components/Routes.razor (100%) rename src/website/tools/{profiler-film => video}/demos/blazor-storefront/Components/_Imports.razor (100%) rename src/website/tools/{profiler-film => video}/demos/blazor-storefront/Directory.Build.props (100%) rename src/website/tools/{profiler-film => video}/demos/blazor-storefront/Program.cs (100%) rename src/website/tools/{profiler-film => video}/demos/fs-storefront/Catalog.fs (100%) rename src/website/tools/{profiler-film => video}/demos/fs-storefront/Checkout.fs (100%) rename src/website/tools/{profiler-film => video}/demos/fs-storefront/Directory.Build.props (100%) rename src/website/tools/{profiler-film => video}/demos/fs-storefront/Domain.fs (100%) rename src/website/tools/{profiler-film => video}/demos/fs-storefront/FsStorefront.fsproj (100%) rename src/website/tools/{profiler-film => video}/demos/fs-storefront/FsStorefront.slnx (100%) rename src/website/tools/{profiler-film => video}/demos/fs-storefront/Program.fs (100%) rename src/website/tools/{profiler-film => video}/demos/fs-storefront/Sessions.fs (100%) rename src/website/tools/{profiler-film => video}/demos/storefront/Catalog.cs (100%) rename src/website/tools/{profiler-film => video}/demos/storefront/CheckoutPipeline.cs (100%) rename src/website/tools/{profiler-film => video}/demos/storefront/Directory.Build.props (100%) rename src/website/tools/{profiler-film => video}/demos/storefront/Program.cs (100%) rename src/website/tools/{profiler-film => video}/demos/storefront/SessionCache.cs (100%) rename src/website/tools/{profiler-film => video}/demos/storefront/Storefront.csproj (100%) rename src/website/tools/{profiler-film => video}/demos/storefront/Storefront.slnx (100%) rename src/website/tools/{profiler-film => video}/film.mjs (90%) rename src/website/tools/{profiler-film => video}/films/architecture.mjs (96%) rename src/website/tools/{profiler-film => video}/films/architecture.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/blazor.mjs (98%) rename src/website/tools/{profiler-film => video}/films/blazor.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/completions.mjs (96%) rename src/website/tools/{profiler-film => video}/films/completions.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/configuration.mjs (97%) rename src/website/tools/{profiler-film => video}/films/configuration.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/context-menus.mjs (96%) rename src/website/tools/{profiler-film => video}/films/context-menus.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/contributing.mjs (97%) rename src/website/tools/{profiler-film => video}/films/contributing.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/csharp.mjs (94%) rename src/website/tools/{profiler-film => video}/films/csharp.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/diagnostics.mjs (97%) rename src/website/tools/{profiler-film => video}/films/diagnostics.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/doc-stills.mjs (99%) rename src/website/tools/{profiler-film => video}/films/editor-setup.mjs (96%) rename src/website/tools/{profiler-film => video}/films/editor-setup.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/fsharp-language.mjs (97%) rename src/website/tools/{profiler-film => video}/films/fsharp-language.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/fsharp.mjs (97%) rename src/website/tools/{profiler-film => video}/films/fsharp.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/getting-started.mjs (96%) rename src/website/tools/{profiler-film => video}/films/getting-started.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/hover.mjs (96%) rename src/website/tools/{profiler-film => video}/films/hover.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/leak.mjs (96%) rename src/website/tools/{profiler-film => video}/films/leak.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/navigation.mjs (96%) rename src/website/tools/{profiler-film => video}/films/navigation.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/nuget.mjs (97%) rename src/website/tools/{profiler-film => video}/films/nuget.narration.json (100%) rename src/website/tools/{profiler-film => video}/films/profiler/capture.mjs (95%) rename src/website/tools/{profiler-film => video}/films/profiler/film.html (100%) rename src/website/tools/{profiler-film => video}/films/profiler/film.js (100%) rename src/website/tools/{profiler-film => video}/films/profiler/flamegraph.mjs (100%) create mode 100644 src/website/tools/video/films/profiler/render.mjs rename src/website/tools/{profiler-film => video}/films/refactoring.mjs (96%) rename src/website/tools/{profiler-film => video}/films/refactoring.narration.json (100%) rename src/website/tools/{hero-netfx-windows.html => video/heroes/netfx-windows.html} (100%) rename src/website/tools/{profiler-film => video}/kit/acts/cpu.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/acts/explorer.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/acts/language.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/acts/memory.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/acts/shop.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/acts/tour.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/camera.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/code.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/editor.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/encode.mjs (100%) create mode 100644 src/website/tools/video/kit/frames.mjs rename src/website/tools/{profiler-film => video}/kit/overlay.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/scenes.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/screencast.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/set.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/sound/score.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/sound/soundtrack.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/sound/voice.mjs (100%) rename src/website/tools/{profiler-film => video}/kit/workbench.mjs (100%) rename src/website/tools/{profiler-film => video}/package-lock.json (99%) rename src/website/tools/{profiler-film => video}/package.json (87%) diff --git a/AGENTS.md b/AGENTS.md index 38ddf783..48057ea3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,6 +3,8 @@ SharpLsp is an open-source, editor-agnostic .NET LSP (C# + F#) built in Rust: one server, the complete .NET development experience in every editor. Stack: C#, Rust, TypeScript +All large files like videos MUST go in Git LFS + **Aim #1: Fix the .NET developer experience.** Match and surpass Visual Studio, Rider, and C# Dev Kit — no proprietary dependencies, licenses, or vendor lock-in. @@ -104,8 +106,9 @@ F# ahead of C# on every new feature. F# never takes the back seat. # Git -> ⛔️ **Don't touch git** unless the user asks or a skill demands it. - +> ⛔️ **Don't make git changes like creating new branches** unless the user asks or a skill demands it. +- Commit and push to submodules before commiting and pushing the feature branch +- Commit and push after each major change - **One feature branch**, never `git worktree`. Work the open one; several open → merge them immediately - **Never push to `main`.** PR → CI green → squash-merge → delete the branch - **Own every PR until green**: `gh pr merge --auto --squash`, then fix and push until all checks pass diff --git a/Makefile b/Makefile index 809dac3f..b8ee1970 100644 --- a/Makefile +++ b/Makefile @@ -807,13 +807,13 @@ _website-dev: # [WEB-DESIGN-MEDIA] Shoot and publish one website film from the packaged VSIX: # `make _film FILM=fsharp`, or `PUBLISH=1` to publish the last shoot again. -# The films live in src/website/tools/profiler-film/films; its README says how. +# The films live in src/website/tools/video/films; its README says how. _film: @test -n "$(FILM)" || { echo "usage: make _film FILM= [PUBLISH=1]" >&2; exit 1; } $(if $(PUBLISH),,$(MAKE) _build-vsix VSIX_PREBUILT=1) @# Install once: npm ci would wipe the voice model kokoro-js caches in node_modules. - test -d src/website/tools/profiler-film/node_modules || npm ci --prefix src/website/tools/profiler-film - node src/website/tools/profiler-film/film.mjs $(FILM) $(if $(PUBLISH),--publish,) + test -d src/website/tools/video/node_modules || npm ci --prefix src/website/tools/video + node src/website/tools/video/film.mjs $(FILM) $(if $(PUBLISH),--publish,) _test-website: @echo "==> Running website Playwright tests..." diff --git a/docs/specs/DESIGN-SYSTEM.md b/docs/specs/DESIGN-SYSTEM.md index 0f70f2fe..0321f93d 100644 --- a/docs/specs/DESIGN-SYSTEM.md +++ b/docs/specs/DESIGN-SYSTEM.md @@ -126,7 +126,7 @@ Page-level grids and marketing card styles must not leak into `.prose`. Do not r Screenshots and video of a SharpLsp feature show the real extension, never a mock-up. -- **Capture.** Product films are shot by `src/website/tools/profiler-film/` (its README says how). Every shot runs on `kit/set.mjs`'s `onSet`: an isolated VS Code (its own user-data and extensions directories, never the user's editor) running the packaged VSIX against a real .NET demo from `demos/`. A walkthrough is one file in `films/`, a list of scenes that `film.mjs` shoots as real-time clips and publishes; `kit/acts/` tells the shared stories (the CPU and memory loops, the language features, the Solution Explorer), so each film supplies only its words, its demo and its edits. The profiler films run on the C# Storefront demo and its F# twin, FsStorefront; the language films run on `Shop.slnx`, both in one solution, and show F# before C#. Every F# claim the docs make is shown on F# code. Every feature page's still, and every figure in the launch post, is shot the same way by `films/doc-stills.mjs`; no page shows a capture from any other source. The composited one-minute film is `films/profiler/`: `capture.mjs` records stills and screencasts, and `render.mjs` turns them into the site's assets. +- **Capture.** Product films are shot by `src/website/tools/video/` (its README says how). Every shot runs on `kit/set.mjs`'s `onSet`: an isolated VS Code (its own user-data and extensions directories, never the user's editor) running the packaged VSIX against a real .NET demo from `demos/`. A walkthrough is one file in `films/`, a list of scenes that `film.mjs` shoots as real-time clips and publishes; `kit/acts/` tells the shared stories (the CPU and memory loops, the language features, the Solution Explorer), so each film supplies only its words, its demo and its edits. The profiler films run on the C# Storefront demo and its F# twin, FsStorefront; the language films run on `Shop.slnx`, both in one solution, and show F# before C#. Every F# claim the docs make is shown on F# code. Every feature page's still, and every figure in the launch post, is shot the same way by `films/doc-stills.mjs`; no page shows a capture from any other source. The composited one-minute film is `films/profiler/`: `capture.mjs` records stills and screencasts, and `render.mjs` turns them into the site's assets. - **Honesty.** Footage plays in real time unless the frame says otherwise: every fast-forwarded stretch carries an on-screen speed marker, and captions name time-lapses. Motion graphics (title cards, camera moves, highlights, the cursor) frame the footage but never alter what the editor shows. - **Privacy.** No frame may show a user name, home directory or hostname. The demo runs from a neutral temporary path, and the editor runs on a copy-on-write clone of the .NET install under that path, with its login-shell environment off, so every path it prints is neutral. A terminal appears only where the feature runs in one (F# Interactive, a build task, a contributor's command line), and a shell terminal starts with no profile and a bare `$ ` prompt. - **Formats.** diff --git a/src/website/tests/profiler-media.spec.js b/src/website/tests/profiler-media.spec.js index 9eb50e3a..7dd78b43 100644 --- a/src/website/tests/profiler-media.spec.js +++ b/src/website/tests/profiler-media.spec.js @@ -1,4 +1,4 @@ -// Tests for [WEB-DESIGN-MEDIA]: the profiler film and stills the profiler-film +// Tests for [WEB-DESIGN-MEDIA]: the profiler film and stills tools/video // tooling renders from the real extension. import { test, expect } from '@playwright/test'; import { expectPlayable, expectStills, playback, sourcesOf } from './media.js'; diff --git a/src/website/tools/profiler-film/films/profiler/render.mjs b/src/website/tools/profiler-film/films/profiler/render.mjs deleted file mode 100644 index 9ee5d6d1..00000000 --- a/src/website/tools/profiler-film/films/profiler/render.mjs +++ /dev/null @@ -1,107 +0,0 @@ -// Implements [WEB-DESIGN-MEDIA]. Renders the profiler film and the website's profiler media from capture.mjs's -// output: steps film.html frame by frame in headless Chromium, pipes the frames -// to ffmpeg, then writes the site assets (film MP4/WebM + poster, the unedited -// recordings + posters, WebP stills). -// -// node src/website/tools/profiler-film/films/profiler/render.mjs -// node src/website/tools/profiler-film/films/profiler/render.mjs --preview 2,9.5,24 (stills of those seconds) -import { spawn } from 'node:child_process'; -import fs from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { chromium } from '@playwright/test'; -import { H264, VP9, ffmpeg, out, poster, publishStills, videos } from '../../kit/encode.mjs'; - -const here = path.dirname(fileURLToPath(import.meta.url)); -const FPS = 30; -const POSTER_AT = 25.5; - -/** Explode a clip into numbered JPEGs the film steps through; returns the frame count. */ -function explode(name) { - const dir = path.join(out, 'film', name); - fs.rmSync(dir, { recursive: true, force: true }); - fs.mkdirSync(dir, { recursive: true }); - ffmpeg(['-i', path.join(out, 'clips', `${name}.mp4`), '-vf', `fps=${FPS}`, '-q:v', '2', path.join(dir, '%05d.jpg')], name); - return fs.readdirSync(dir).filter((file) => file.endsWith('.jpg')).length; -} - -function filmData() { - const clip = (name) => ({ - frames: explode(name), - cues: JSON.parse(fs.readFileSync(path.join(out, 'clips', `${name}.cues.json`), 'utf8')), - }); - return { cpu: clip('cpu'), memory: clip('memory') }; -} - -/** Open the film page with the clips' data; resolves to the page and the film's length. */ -async function openFilm(browser) { - const page = await browser.newPage({ viewport: { width: 1920, height: 1080 }, deviceScaleFactor: 1 }); - await page.addInitScript((film) => { - window.FILM_DATA = film; - }, filmData()); - await page.goto(`file://${path.join(here, 'film.html')}`); - await page.evaluate(() => document.fonts.ready); - const [duration, scenes] = await page.evaluate(() => [window.FILM_DURATION, window.FILM_SCENES]); - process.stdout.write(`${JSON.stringify(scenes)}\n`); - return { page, duration }; -} - -async function preview(times) { - const browser = await chromium.launch(); - const { page, duration } = await openFilm(browser); - fs.mkdirSync(path.join(out, 'preview'), { recursive: true }); - for (const t of times) { - await page.evaluate((at) => window.renderFrame(at), t); - await page.screenshot({ path: path.join(out, 'preview', `${t}.png`) }); - } - await browser.close(); - process.stdout.write(`film is ${duration.toFixed(1)}s; previews in out/preview\n`); -} - -/** Step the film and pipe every frame, losslessly, into the master encode. */ -async function renderMaster(master) { - const browser = await chromium.launch(); - const { page, duration } = await openFilm(browser); - const encoder = spawn('ffmpeg', [ - '-y', '-loglevel', 'error', '-f', 'image2pipe', '-framerate', String(FPS), '-c:v', 'png', '-i', '-', - '-c:v', 'libx264', '-preset', 'slow', '-crf', '12', '-pix_fmt', 'yuv420p', master, - ], { stdio: ['pipe', 'inherit', 'inherit'] }); - const done = new Promise((resolve, reject) => encoder.once('exit', (code) => (code === 0 ? resolve() : reject(new Error(`master encode exited ${code}`))))); - for (let frame = 0; frame < Math.ceil(duration * FPS); frame++) { - await page.evaluate((t) => window.renderFrame(t), frame / FPS); - if (!encoder.stdin.write(await page.screenshot({ type: 'png' }))) await new Promise((r) => encoder.stdin.once('drain', r)); - } - encoder.stdin.end(); - await done; - await browser.close(); - return duration; -} - -/** The site's film: H.264 for reach, VP9 for size, and a poster frame. */ -function publishFilm(master) { - ffmpeg(['-i', master, ...H264, path.join(videos, 'profiler-film.mp4')], 'film mp4'); - ffmpeg(['-i', master, ...VP9, path.join(videos, 'profiler-film.webm')], 'film webm'); - poster(master, POSTER_AT, 'profiler-film'); -} - -/** The unedited recordings: CPU in real time, memory as a 3x time-lapse. */ -function publishRecordings() { - ffmpeg(['-i', path.join(out, 'clips/cpu.mp4'), '-vf', 'scale=1920:-2:flags=lanczos', ...H264, path.join(videos, 'profiler-cpu-recording.mp4')], 'cpu recording'); - ffmpeg(['-i', path.join(out, 'clips/memory.mp4'), '-vf', 'setpts=PTS/3,fps=30,scale=1920:-2:flags=lanczos', ...H264, path.join(videos, 'profiler-memory-timelapse.mp4')], 'memory recording'); - poster(path.join(videos, 'profiler-cpu-recording.mp4'), 16, 'profiler-cpu-recording'); - poster(path.join(videos, 'profiler-memory-timelapse.mp4'), 14, 'profiler-memory-timelapse'); -} - -async function main() { - const flag = process.argv.indexOf('--preview'); - if (flag > 0) return preview(process.argv[flag + 1].split(',').map(Number)); - fs.mkdirSync(videos, { recursive: true }); - const master = path.join(out, 'film-master.mp4'); - const duration = await renderMaster(master); - publishFilm(master); - publishRecordings(); - publishStills(path.join(out, 'stills')); - process.stdout.write(`rendered ${duration.toFixed(1)}s film and the profiler media\n`); -} - -await main(); diff --git a/src/website/tools/profiler-film/.gitignore b/src/website/tools/video/.gitignore similarity index 100% rename from src/website/tools/profiler-film/.gitignore rename to src/website/tools/video/.gitignore diff --git a/src/website/tools/profiler-film/README.md b/src/website/tools/video/README.md similarity index 87% rename from src/website/tools/profiler-film/README.md rename to src/website/tools/video/README.md index e7f2a124..337bfd7e 100644 --- a/src/website/tools/profiler-film/README.md +++ b/src/website/tools/video/README.md @@ -1,6 +1,6 @@ -# Profiler films +# Videos -This folder holds the scripts that shoot and publish the videos and stills on sharplsp.dev. Every frame is the real extension: an isolated VS Code (its own user data and extensions, never yours) runs the packaged VSIX against a demo app. Nothing in the editor is mocked. The rules are in [WEB-DESIGN-MEDIA](../../../../docs/specs/DESIGN-SYSTEM.md). +Every video and still on sharplsp.dev is made here, on one shared kit: the walkthroughs, the composited profiler film, the lessons and the blog heroes. Every frame is the real extension: an isolated VS Code (its own user data and extensions, never yours) runs the packaged VSIX against a demo app. Nothing in the editor is mocked. The rules are in [WEB-DESIGN-MEDIA](../../../../docs/specs/DESIGN-SYSTEM.md). ## Make a film @@ -8,7 +8,7 @@ You need a packaged VSIX, ffmpeg with libvpx and libopus, cwebp, and the .NET 10 ```sh npm ci --prefix src/website # Playwright -npm ci --prefix src/website/tools/profiler-film # kokoro-js, for narration +npm ci --prefix src/website/tools/video # kokoro-js, for narration ``` The first narrated publish downloads the voice model (about 310 MB) into `node_modules`; a later `npm ci` there deletes it again. @@ -20,7 +20,7 @@ make _film FILM=fsharp # package the VSIX, shoot, then publish make _film FILM=fsharp PUBLISH=1 # publish the last shoot again ``` -`make _film` runs `node src/website/tools/profiler-film/film.mjs [--publish]`, which you can also call directly after `make _build-vsix VSIX_PREBUILT=1`. +`make _film` runs `node src/website/tools/video/film.mjs [--publish]`, which you can also call directly after `make _build-vsix VSIX_PREBUILT=1`. A shoot takes a few minutes and lands in `out//`, which is gitignored. Publishing writes the MP4, WebM, poster, captions and stills into `src/website/src/assets/`. Add or update the video's entry in `src/website/src/_data/videos.json` (its length, its upload date, and its label and caption in each language), then place it on a page with `{% video "" %}`. @@ -93,6 +93,7 @@ The kit tells the common stories, so a film only supplies its words: | `kit/workbench.mjs` | Editor moves: the Processes view and its demo row, `openFile`, `goTo`, `typeAt`, `toggleMaximised`, `panel` and more | | `kit/camera.mjs` | `snap(shot, name)` takes a still, published as `.webp` | | `kit/set.mjs` | The sets (`STOREFRONT`, `FS_STOREFRONT`, `SHOP` with both in one solution, and `REPO`, a clean copy of this repository) and `onSet`, which stages one beside an isolated editor | +| `kit/frames.mjs` | `explode` (footage into numbered frames) and `renderMaster` / `previewFrames`: step a page whose `renderFrame(t)` draws every frame, into a lossless master. The profiler film and the lessons render through it | | `kit/sound/` | Narration (`voice.mjs`), the original score (`score.mjs`) and the mix (`soundtrack.mjs`) | A new demo app goes in `demos//`, with one project and an empty `Directory.Build.props`, and is declared in `kit/set.mjs`. It must print a line to stdout once it is running. @@ -117,3 +118,7 @@ A narrated film has a script next to it, `films/.narration.json`: - **Timing.** Each line starts just after its scene's cut. A scene holds its last frame until its line has been spoken, so keep lines about as long as their scenes. - **Music.** `kit/sound/score.mjs` synthesises an original score, so no film carries licensed music. It ducks under the voice, and the mix is normalised to -16 LUFS. - **Captions.** Every language in `music` gets WebVTT captions, `..vtt`. List those languages under `captions` in `videos.json`, and the page's own language shows by default. + +## Heroes + +`heroes/` holds the blog posts' hero images as HTML pages, one per post, sized to the hero (1672x941). Screenshot the page at that size and publish it as WebP. diff --git a/src/website/tools/profiler-film/demos/Shop.slnx b/src/website/tools/video/demos/Shop.slnx similarity index 100% rename from src/website/tools/profiler-film/demos/Shop.slnx rename to src/website/tools/video/demos/Shop.slnx diff --git a/src/website/tools/profiler-film/demos/blazor-storefront/BlazorStorefront.csproj b/src/website/tools/video/demos/blazor-storefront/BlazorStorefront.csproj similarity index 100% rename from src/website/tools/profiler-film/demos/blazor-storefront/BlazorStorefront.csproj rename to src/website/tools/video/demos/blazor-storefront/BlazorStorefront.csproj diff --git a/src/website/tools/profiler-film/demos/blazor-storefront/BlazorStorefront.slnx b/src/website/tools/video/demos/blazor-storefront/BlazorStorefront.slnx similarity index 100% rename from src/website/tools/profiler-film/demos/blazor-storefront/BlazorStorefront.slnx rename to src/website/tools/video/demos/blazor-storefront/BlazorStorefront.slnx diff --git a/src/website/tools/profiler-film/demos/blazor-storefront/Catalog.cs b/src/website/tools/video/demos/blazor-storefront/Catalog.cs similarity index 100% rename from src/website/tools/profiler-film/demos/blazor-storefront/Catalog.cs rename to src/website/tools/video/demos/blazor-storefront/Catalog.cs diff --git a/src/website/tools/profiler-film/demos/blazor-storefront/Components/App.razor b/src/website/tools/video/demos/blazor-storefront/Components/App.razor similarity index 100% rename from src/website/tools/profiler-film/demos/blazor-storefront/Components/App.razor rename to src/website/tools/video/demos/blazor-storefront/Components/App.razor diff --git a/src/website/tools/profiler-film/demos/blazor-storefront/Components/Layout/MainLayout.razor b/src/website/tools/video/demos/blazor-storefront/Components/Layout/MainLayout.razor similarity index 100% rename from src/website/tools/profiler-film/demos/blazor-storefront/Components/Layout/MainLayout.razor rename to src/website/tools/video/demos/blazor-storefront/Components/Layout/MainLayout.razor diff --git a/src/website/tools/profiler-film/demos/blazor-storefront/Components/Pages/Basket.razor b/src/website/tools/video/demos/blazor-storefront/Components/Pages/Basket.razor similarity index 100% rename from src/website/tools/profiler-film/demos/blazor-storefront/Components/Pages/Basket.razor rename to src/website/tools/video/demos/blazor-storefront/Components/Pages/Basket.razor diff --git a/src/website/tools/profiler-film/demos/blazor-storefront/Components/Routes.razor b/src/website/tools/video/demos/blazor-storefront/Components/Routes.razor similarity index 100% rename from src/website/tools/profiler-film/demos/blazor-storefront/Components/Routes.razor rename to src/website/tools/video/demos/blazor-storefront/Components/Routes.razor diff --git a/src/website/tools/profiler-film/demos/blazor-storefront/Components/_Imports.razor b/src/website/tools/video/demos/blazor-storefront/Components/_Imports.razor similarity index 100% rename from src/website/tools/profiler-film/demos/blazor-storefront/Components/_Imports.razor rename to src/website/tools/video/demos/blazor-storefront/Components/_Imports.razor diff --git a/src/website/tools/profiler-film/demos/blazor-storefront/Directory.Build.props b/src/website/tools/video/demos/blazor-storefront/Directory.Build.props similarity index 100% rename from src/website/tools/profiler-film/demos/blazor-storefront/Directory.Build.props rename to src/website/tools/video/demos/blazor-storefront/Directory.Build.props diff --git a/src/website/tools/profiler-film/demos/blazor-storefront/Program.cs b/src/website/tools/video/demos/blazor-storefront/Program.cs similarity index 100% rename from src/website/tools/profiler-film/demos/blazor-storefront/Program.cs rename to src/website/tools/video/demos/blazor-storefront/Program.cs diff --git a/src/website/tools/profiler-film/demos/fs-storefront/Catalog.fs b/src/website/tools/video/demos/fs-storefront/Catalog.fs similarity index 100% rename from src/website/tools/profiler-film/demos/fs-storefront/Catalog.fs rename to src/website/tools/video/demos/fs-storefront/Catalog.fs diff --git a/src/website/tools/profiler-film/demos/fs-storefront/Checkout.fs b/src/website/tools/video/demos/fs-storefront/Checkout.fs similarity index 100% rename from src/website/tools/profiler-film/demos/fs-storefront/Checkout.fs rename to src/website/tools/video/demos/fs-storefront/Checkout.fs diff --git a/src/website/tools/profiler-film/demos/fs-storefront/Directory.Build.props b/src/website/tools/video/demos/fs-storefront/Directory.Build.props similarity index 100% rename from src/website/tools/profiler-film/demos/fs-storefront/Directory.Build.props rename to src/website/tools/video/demos/fs-storefront/Directory.Build.props diff --git a/src/website/tools/profiler-film/demos/fs-storefront/Domain.fs b/src/website/tools/video/demos/fs-storefront/Domain.fs similarity index 100% rename from src/website/tools/profiler-film/demos/fs-storefront/Domain.fs rename to src/website/tools/video/demos/fs-storefront/Domain.fs diff --git a/src/website/tools/profiler-film/demos/fs-storefront/FsStorefront.fsproj b/src/website/tools/video/demos/fs-storefront/FsStorefront.fsproj similarity index 100% rename from src/website/tools/profiler-film/demos/fs-storefront/FsStorefront.fsproj rename to src/website/tools/video/demos/fs-storefront/FsStorefront.fsproj diff --git a/src/website/tools/profiler-film/demos/fs-storefront/FsStorefront.slnx b/src/website/tools/video/demos/fs-storefront/FsStorefront.slnx similarity index 100% rename from src/website/tools/profiler-film/demos/fs-storefront/FsStorefront.slnx rename to src/website/tools/video/demos/fs-storefront/FsStorefront.slnx diff --git a/src/website/tools/profiler-film/demos/fs-storefront/Program.fs b/src/website/tools/video/demos/fs-storefront/Program.fs similarity index 100% rename from src/website/tools/profiler-film/demos/fs-storefront/Program.fs rename to src/website/tools/video/demos/fs-storefront/Program.fs diff --git a/src/website/tools/profiler-film/demos/fs-storefront/Sessions.fs b/src/website/tools/video/demos/fs-storefront/Sessions.fs similarity index 100% rename from src/website/tools/profiler-film/demos/fs-storefront/Sessions.fs rename to src/website/tools/video/demos/fs-storefront/Sessions.fs diff --git a/src/website/tools/profiler-film/demos/storefront/Catalog.cs b/src/website/tools/video/demos/storefront/Catalog.cs similarity index 100% rename from src/website/tools/profiler-film/demos/storefront/Catalog.cs rename to src/website/tools/video/demos/storefront/Catalog.cs diff --git a/src/website/tools/profiler-film/demos/storefront/CheckoutPipeline.cs b/src/website/tools/video/demos/storefront/CheckoutPipeline.cs similarity index 100% rename from src/website/tools/profiler-film/demos/storefront/CheckoutPipeline.cs rename to src/website/tools/video/demos/storefront/CheckoutPipeline.cs diff --git a/src/website/tools/profiler-film/demos/storefront/Directory.Build.props b/src/website/tools/video/demos/storefront/Directory.Build.props similarity index 100% rename from src/website/tools/profiler-film/demos/storefront/Directory.Build.props rename to src/website/tools/video/demos/storefront/Directory.Build.props diff --git a/src/website/tools/profiler-film/demos/storefront/Program.cs b/src/website/tools/video/demos/storefront/Program.cs similarity index 100% rename from src/website/tools/profiler-film/demos/storefront/Program.cs rename to src/website/tools/video/demos/storefront/Program.cs diff --git a/src/website/tools/profiler-film/demos/storefront/SessionCache.cs b/src/website/tools/video/demos/storefront/SessionCache.cs similarity index 100% rename from src/website/tools/profiler-film/demos/storefront/SessionCache.cs rename to src/website/tools/video/demos/storefront/SessionCache.cs diff --git a/src/website/tools/profiler-film/demos/storefront/Storefront.csproj b/src/website/tools/video/demos/storefront/Storefront.csproj similarity index 100% rename from src/website/tools/profiler-film/demos/storefront/Storefront.csproj rename to src/website/tools/video/demos/storefront/Storefront.csproj diff --git a/src/website/tools/profiler-film/demos/storefront/Storefront.slnx b/src/website/tools/video/demos/storefront/Storefront.slnx similarity index 100% rename from src/website/tools/profiler-film/demos/storefront/Storefront.slnx rename to src/website/tools/video/demos/storefront/Storefront.slnx diff --git a/src/website/tools/profiler-film/film.mjs b/src/website/tools/video/film.mjs similarity index 90% rename from src/website/tools/profiler-film/film.mjs rename to src/website/tools/video/film.mjs index e0554f50..332f136c 100644 --- a/src/website/tools/profiler-film/film.mjs +++ b/src/website/tools/video/film.mjs @@ -2,8 +2,8 @@ // films/.mjs. See README.md. // // make _build-vsix VSIX_PREBUILT=1 -// node src/website/tools/profiler-film/film.mjs (shoot, then publish) -// node src/website/tools/profiler-film/film.mjs --publish (publish the last shoot) +// node src/website/tools/video/film.mjs (shoot, then publish) +// node src/website/tools/video/film.mjs --publish (publish the last shoot) // // A shoot lands in out// (gitignored); publishing writes the site's video, // poster, captions and stills under src/website/src/assets. diff --git a/src/website/tools/profiler-film/films/architecture.mjs b/src/website/tools/video/films/architecture.mjs similarity index 96% rename from src/website/tools/profiler-film/films/architecture.mjs rename to src/website/tools/video/films/architecture.mjs index d2feadec..f30d89ce 100644 --- a/src/website/tools/profiler-film/films/architecture.mjs +++ b/src/website/tools/video/films/architecture.mjs @@ -3,7 +3,7 @@ // F# hover to the F# Compiler Service and a C# hover to Roslyn; then folding, // answered by tree-sitter in the host with no engine involved. // -// node src/website/tools/profiler-film/film.mjs architecture +// node src/website/tools/video/film.mjs architecture import { LANGUAGE, hoverEach, scene, showLog } from '../kit/acts/language.mjs'; import { AT_CHECKOUT, AT_PIPELINE, ready } from '../kit/acts/shop.mjs'; import { SHOP } from '../kit/set.mjs'; diff --git a/src/website/tools/profiler-film/films/architecture.narration.json b/src/website/tools/video/films/architecture.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/architecture.narration.json rename to src/website/tools/video/films/architecture.narration.json diff --git a/src/website/tools/profiler-film/films/blazor.mjs b/src/website/tools/video/films/blazor.mjs similarity index 98% rename from src/website/tools/profiler-film/films/blazor.mjs rename to src/website/tools/video/films/blazor.mjs index 343011ad..add86672 100644 --- a/src/website/tools/profiler-film/films/blazor.mjs +++ b/src/website/tools/video/films/blazor.mjs @@ -4,7 +4,7 @@ // VS Code's own HTML service, a component's definition reached from C#, and // linked tag editing and folding. // -// node src/website/tools/profiler-film/film.mjs blazor +// node src/website/tools/video/film.mjs blazor import { snap } from '../kit/camera.mjs'; import { clickOn, hoverOn } from '../kit/code.mjs'; import { LANGUAGE, hidePanel, hoverEach, navigate, peekReferences, renameTo, scene, typeText, typeThroughCompletion } from '../kit/acts/language.mjs'; diff --git a/src/website/tools/profiler-film/films/blazor.narration.json b/src/website/tools/video/films/blazor.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/blazor.narration.json rename to src/website/tools/video/films/blazor.narration.json diff --git a/src/website/tools/profiler-film/films/completions.mjs b/src/website/tools/video/films/completions.mjs similarity index 96% rename from src/website/tools/profiler-film/films/completions.mjs rename to src/website/tools/video/films/completions.mjs index 1614e7c6..3464cdab 100644 --- a/src/website/tools/profiler-film/films/completions.mjs +++ b/src/website/tools/video/films/completions.mjs @@ -2,7 +2,7 @@ // (`code-completions`): F# and C# member completion typed live, then a type // from a namespace the file never imported, with its using added. // -// node src/website/tools/profiler-film/film.mjs completions +// node src/website/tools/video/film.mjs completions import { clickOn } from '../kit/code.mjs'; import { LANGUAGE, complete, scene, typeText } from '../kit/acts/language.mjs'; import { AT_CHECKOUT, AT_PIPELINE, csharpCheapest, fsharpCheapest, ready } from '../kit/acts/shop.mjs'; diff --git a/src/website/tools/profiler-film/films/completions.narration.json b/src/website/tools/video/films/completions.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/completions.narration.json rename to src/website/tools/video/films/completions.narration.json diff --git a/src/website/tools/profiler-film/films/configuration.mjs b/src/website/tools/video/films/configuration.mjs similarity index 97% rename from src/website/tools/profiler-film/films/configuration.mjs rename to src/website/tools/video/films/configuration.mjs index 3518fc11..e0ce42d5 100644 --- a/src/website/tools/profiler-film/films/configuration.mjs +++ b/src/website/tools/video/films/configuration.mjs @@ -3,7 +3,7 @@ // the solution, monorepo mode switched on, the server restarted, and an // unused public property reported as dead code. // -// node src/website/tools/profiler-film/film.mjs configuration +// node src/website/tools/video/film.mjs configuration import fs from 'node:fs'; import path from 'node:path'; import { runCommand } from '../kit/editor.mjs'; diff --git a/src/website/tools/profiler-film/films/configuration.narration.json b/src/website/tools/video/films/configuration.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/configuration.narration.json rename to src/website/tools/video/films/configuration.narration.json diff --git a/src/website/tools/profiler-film/films/context-menus.mjs b/src/website/tools/video/films/context-menus.mjs similarity index 96% rename from src/website/tools/profiler-film/films/context-menus.mjs rename to src/website/tools/video/films/context-menus.mjs index d2e92ed6..5d535284 100644 --- a/src/website/tools/profiler-film/films/context-menus.mjs +++ b/src/website/tools/video/films/context-menus.mjs @@ -2,7 +2,7 @@ // (`context-menus`): the Solution Explorer's menus on the solution, a // project (Build, Open Project File) and a C# type (Sort Members). // -// node src/website/tools/profiler-film/film.mjs context-menus +// node src/website/tools/video/film.mjs context-menus import { LANGUAGE, scene } from '../kit/acts/language.mjs'; import { openMenu, pickMenu, unfold } from '../kit/acts/explorer.mjs'; import { AT_PROGRAM_CS, ready } from '../kit/acts/shop.mjs'; diff --git a/src/website/tools/profiler-film/films/context-menus.narration.json b/src/website/tools/video/films/context-menus.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/context-menus.narration.json rename to src/website/tools/video/films/context-menus.narration.json diff --git a/src/website/tools/profiler-film/films/contributing.mjs b/src/website/tools/video/films/contributing.mjs similarity index 97% rename from src/website/tools/profiler-film/films/contributing.mjs rename to src/website/tools/video/films/contributing.mjs index 5c942042..8cb262c3 100644 --- a/src/website/tools/profiler-film/films/contributing.mjs +++ b/src/website/tools/video/films/contributing.mjs @@ -3,7 +3,7 @@ // test suite (the Rust host's unit tests) built and run from a terminal, on a // clean copy of the committed tree. // -// node src/website/tools/profiler-film/film.mjs contributing +// node src/website/tools/video/film.mjs contributing import { spawnSync } from 'node:child_process'; import { runCommand } from '../kit/editor.mjs'; import { scene, typeText } from '../kit/acts/language.mjs'; diff --git a/src/website/tools/profiler-film/films/contributing.narration.json b/src/website/tools/video/films/contributing.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/contributing.narration.json rename to src/website/tools/video/films/contributing.narration.json diff --git a/src/website/tools/profiler-film/films/csharp.mjs b/src/website/tools/video/films/csharp.mjs similarity index 94% rename from src/website/tools/profiler-film/films/csharp.mjs rename to src/website/tools/video/films/csharp.mjs index d2c5992e..beff31e8 100644 --- a/src/website/tools/profiler-film/films/csharp.mjs +++ b/src/website/tools/video/films/csharp.mjs @@ -3,7 +3,7 @@ // memory: the leak suspect, the static field that roots it, the fix, and a // second run. The memory half is the leak film's story. // -// node src/website/tools/profiler-film/film.mjs csharp +// node src/website/tools/video/film.mjs csharp import { profilerTour } from '../kit/acts/tour.mjs'; import { STOREFRONT } from '../kit/set.mjs'; import { leakStory } from './leak.mjs'; diff --git a/src/website/tools/profiler-film/films/csharp.narration.json b/src/website/tools/video/films/csharp.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/csharp.narration.json rename to src/website/tools/video/films/csharp.narration.json diff --git a/src/website/tools/profiler-film/films/diagnostics.mjs b/src/website/tools/video/films/diagnostics.mjs similarity index 97% rename from src/website/tools/profiler-film/films/diagnostics.mjs rename to src/website/tools/video/films/diagnostics.mjs index b183246b..51011c75 100644 --- a/src/website/tools/profiler-film/films/diagnostics.mjs +++ b/src/website/tools/video/films/diagnostics.mjs @@ -2,7 +2,7 @@ // (`diagnostics`): errors and SharpLsp's analyzer findings on unsaved F# and // C# edits, each read by hovering it, then the Problems panel that lists them. // -// node src/website/tools/profiler-film/film.mjs diagnostics +// node src/website/tools/video/film.mjs diagnostics import { LANGUAGE, hoverEach, scene } from '../kit/acts/language.mjs'; import { AT_CHECKOUT, AT_PIPELINE, ready } from '../kit/acts/shop.mjs'; import { SHOP } from '../kit/set.mjs'; diff --git a/src/website/tools/profiler-film/films/diagnostics.narration.json b/src/website/tools/video/films/diagnostics.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/diagnostics.narration.json rename to src/website/tools/video/films/diagnostics.narration.json diff --git a/src/website/tools/profiler-film/films/doc-stills.mjs b/src/website/tools/video/films/doc-stills.mjs similarity index 99% rename from src/website/tools/profiler-film/films/doc-stills.mjs rename to src/website/tools/video/films/doc-stills.mjs index 6ba233a9..4f783832 100644 --- a/src/website/tools/profiler-film/films/doc-stills.mjs +++ b/src/website/tools/video/films/doc-stills.mjs @@ -2,7 +2,7 @@ // (`screenshots/docs/.webp`), shot on the Shop demo in the same isolated // editor as the films: no clips, only clean frames of each feature at work. // -// node src/website/tools/profiler-film/film.mjs doc-stills +// node src/website/tools/video/film.mjs doc-stills import fs from 'node:fs'; import path from 'node:path'; import { snap } from '../kit/camera.mjs'; diff --git a/src/website/tools/profiler-film/films/editor-setup.mjs b/src/website/tools/video/films/editor-setup.mjs similarity index 96% rename from src/website/tools/profiler-film/films/editor-setup.mjs rename to src/website/tools/video/films/editor-setup.mjs index 15de5b1d..6827630f 100644 --- a/src/website/tools/profiler-film/films/editor-setup.mjs +++ b/src/website/tools/video/films/editor-setup.mjs @@ -3,7 +3,7 @@ // everything it adds under SharpLsp in the Command Palette, and the // trusted-workspace settings for development builds. // -// node src/website/tools/profiler-film/film.mjs editor-setup +// node src/website/tools/video/film.mjs editor-setup import { runCommand } from '../kit/editor.mjs'; import { LANGUAGE, awaitSemantics, prepareCode, scene, settingsEditor, typeText } from '../kit/acts/language.mjs'; import { pointAt } from '../kit/overlay.mjs'; diff --git a/src/website/tools/profiler-film/films/editor-setup.narration.json b/src/website/tools/video/films/editor-setup.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/editor-setup.narration.json rename to src/website/tools/video/films/editor-setup.narration.json diff --git a/src/website/tools/profiler-film/films/fsharp-language.mjs b/src/website/tools/video/films/fsharp-language.mjs similarity index 97% rename from src/website/tools/profiler-film/films/fsharp-language.mjs rename to src/website/tools/video/films/fsharp-language.mjs index 41b9ca93..71dd944c 100644 --- a/src/website/tools/profiler-film/films/fsharp-language.mjs +++ b/src/website/tools/video/films/fsharp-language.mjs @@ -3,7 +3,7 @@ // references, a generated match case, a rename across files, and F# // Interactive, all on FsStorefront in the Shop solution. // -// node src/website/tools/profiler-film/film.mjs fsharp-language +// node src/website/tools/video/film.mjs fsharp-language import { runCommand } from '../kit/editor.mjs'; import { LANGUAGE, hoverEach, navigate, peekReferences, scene, typeText } from '../kit/acts/language.mjs'; import { AT_CHECKOUT, fsharpCheapest, missingCase, ready, renameAcrossFiles } from '../kit/acts/shop.mjs'; diff --git a/src/website/tools/profiler-film/films/fsharp-language.narration.json b/src/website/tools/video/films/fsharp-language.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/fsharp-language.narration.json rename to src/website/tools/video/films/fsharp-language.narration.json diff --git a/src/website/tools/profiler-film/films/fsharp.mjs b/src/website/tools/video/films/fsharp.mjs similarity index 97% rename from src/website/tools/profiler-film/films/fsharp.mjs rename to src/website/tools/video/films/fsharp.mjs index d451aed9..029bc32c 100644 --- a/src/website/tools/profiler-film/films/fsharp.mjs +++ b/src/website/tools/video/films/fsharp.mjs @@ -3,7 +3,7 @@ // stages, then its memory: records and union cases painted where the code // builds them, the module value that roots the leak, the fix, and a second run. // -// node src/website/tools/profiler-film/film.mjs fsharp +// node src/website/tools/video/film.mjs fsharp import { snap } from '../kit/camera.mjs'; import { profilerTour } from '../kit/acts/tour.mjs'; import { FS_STOREFRONT } from '../kit/set.mjs'; diff --git a/src/website/tools/profiler-film/films/fsharp.narration.json b/src/website/tools/video/films/fsharp.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/fsharp.narration.json rename to src/website/tools/video/films/fsharp.narration.json diff --git a/src/website/tools/profiler-film/films/getting-started.mjs b/src/website/tools/video/films/getting-started.mjs similarity index 96% rename from src/website/tools/profiler-film/films/getting-started.mjs rename to src/website/tools/video/films/getting-started.mjs index 63b974d9..bf21ebf7 100644 --- a/src/website/tools/profiler-film/films/getting-started.mjs +++ b/src/website/tools/video/films/getting-started.mjs @@ -3,7 +3,7 @@ // and F# side by side, an F# hover, a C# completion, and the tools that ship // with the extension. // -// node src/website/tools/profiler-film/film.mjs getting-started +// node src/website/tools/video/film.mjs getting-started import { LANGUAGE, hoverEach, scene, setPane } from '../kit/acts/language.mjs'; import { unfold } from '../kit/acts/explorer.mjs'; import { AT_CHECKOUT, AT_PIPELINE, csharpCheapest, ready } from '../kit/acts/shop.mjs'; diff --git a/src/website/tools/profiler-film/films/getting-started.narration.json b/src/website/tools/video/films/getting-started.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/getting-started.narration.json rename to src/website/tools/video/films/getting-started.narration.json diff --git a/src/website/tools/profiler-film/films/hover.mjs b/src/website/tools/video/films/hover.mjs similarity index 96% rename from src/website/tools/profiler-film/films/hover.mjs rename to src/website/tools/video/films/hover.mjs index 3e2f2d7b..fe9dbfed 100644 --- a/src/website/tools/profiler-film/films/hover.mjs +++ b/src/website/tools/video/films/hover.mjs @@ -2,7 +2,7 @@ // (`hover`): F# signatures and doc comments, union cases and .NET types, C# // XML docs and the type behind `var`, and a hover that reads unsaved edits. // -// node src/website/tools/profiler-film/film.mjs hover +// node src/website/tools/video/film.mjs hover import { hoverOn } from '../kit/code.mjs'; import { LANGUAGE, hoverEach, scene } from '../kit/acts/language.mjs'; import { AT_PROGRAM_CS, AT_PROGRAM_FS, ready } from '../kit/acts/shop.mjs'; diff --git a/src/website/tools/profiler-film/films/hover.narration.json b/src/website/tools/video/films/hover.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/hover.narration.json rename to src/website/tools/video/films/hover.narration.json diff --git a/src/website/tools/profiler-film/films/leak.mjs b/src/website/tools/video/films/leak.mjs similarity index 96% rename from src/website/tools/profiler-film/films/leak.mjs rename to src/website/tools/video/films/leak.mjs index e1bfbdea..26477146 100644 --- a/src/website/tools/profiler-film/films/leak.mjs +++ b/src/website/tools/video/films/leak.mjs @@ -3,7 +3,7 @@ // followed to the static field that roots it, the fix typed in, the fixed build // tracked again. // -// node src/website/tools/profiler-film/film.mjs leak +// node src/website/tools/video/film.mjs leak import { memoryLoop } from '../kit/acts/memory.mjs'; import { prepare } from '../kit/scenes.mjs'; import { STOREFRONT } from '../kit/set.mjs'; diff --git a/src/website/tools/profiler-film/films/leak.narration.json b/src/website/tools/video/films/leak.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/leak.narration.json rename to src/website/tools/video/films/leak.narration.json diff --git a/src/website/tools/profiler-film/films/navigation.mjs b/src/website/tools/video/films/navigation.mjs similarity index 96% rename from src/website/tools/profiler-film/films/navigation.mjs rename to src/website/tools/video/films/navigation.mjs index 276ee6cf..e91c47f1 100644 --- a/src/website/tools/profiler-film/films/navigation.mjs +++ b/src/website/tools/video/films/navigation.mjs @@ -2,7 +2,7 @@ // (`navigation`): definitions in F# and C#, references in a peek window, and // a framework type opened as decompiled source. // -// node src/website/tools/profiler-film/film.mjs navigation +// node src/website/tools/video/film.mjs navigation import { LANGUAGE, navigate, peekReferences, scene } from '../kit/acts/language.mjs'; import { AT_PROGRAM_CS, AT_SESSIONS, ready } from '../kit/acts/shop.mjs'; import { SHOP } from '../kit/set.mjs'; diff --git a/src/website/tools/profiler-film/films/navigation.narration.json b/src/website/tools/video/films/navigation.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/navigation.narration.json rename to src/website/tools/video/films/navigation.narration.json diff --git a/src/website/tools/profiler-film/films/nuget.mjs b/src/website/tools/video/films/nuget.mjs similarity index 97% rename from src/website/tools/profiler-film/films/nuget.mjs rename to src/website/tools/video/films/nuget.mjs index 9bb50dab..5ecfe5f8 100644 --- a/src/website/tools/profiler-film/films/nuget.mjs +++ b/src/website/tools/video/films/nuget.mjs @@ -2,7 +2,7 @@ // (`nuget`): the browser opened on the F# project, a package found on // nuget.org, installed and restored, and its reference in the project file. // -// node src/website/tools/profiler-film/film.mjs nuget +// node src/website/tools/video/film.mjs nuget import { LANGUAGE, scene, typeText } from '../kit/acts/language.mjs'; import { openMenu, pickMenu } from '../kit/acts/explorer.mjs'; import { ringClick } from '../kit/overlay.mjs'; diff --git a/src/website/tools/profiler-film/films/nuget.narration.json b/src/website/tools/video/films/nuget.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/nuget.narration.json rename to src/website/tools/video/films/nuget.narration.json diff --git a/src/website/tools/profiler-film/films/profiler/capture.mjs b/src/website/tools/video/films/profiler/capture.mjs similarity index 95% rename from src/website/tools/profiler-film/films/profiler/capture.mjs rename to src/website/tools/video/films/profiler/capture.mjs index 5a65e234..04c8237c 100644 --- a/src/website/tools/profiler-film/films/profiler/capture.mjs +++ b/src/website/tools/video/films/profiler/capture.mjs @@ -3,9 +3,9 @@ // and real-time screencast clips, plus the click cues the film's cursor follows. // // make _build-vsix VSIX_PREBUILT=1 -// node src/website/tools/profiler-film/films/profiler/capture.mjs +// node src/website/tools/video/films/profiler/capture.mjs // -// Output lands in tools/profiler-film/out/ (gitignored); render.mjs turns it into +// Output lands in tools/video/out/ (gitignored); render.mjs turns it into // the website's assets. import fs from 'node:fs'; import path from 'node:path'; diff --git a/src/website/tools/profiler-film/films/profiler/film.html b/src/website/tools/video/films/profiler/film.html similarity index 100% rename from src/website/tools/profiler-film/films/profiler/film.html rename to src/website/tools/video/films/profiler/film.html diff --git a/src/website/tools/profiler-film/films/profiler/film.js b/src/website/tools/video/films/profiler/film.js similarity index 100% rename from src/website/tools/profiler-film/films/profiler/film.js rename to src/website/tools/video/films/profiler/film.js diff --git a/src/website/tools/profiler-film/films/profiler/flamegraph.mjs b/src/website/tools/video/films/profiler/flamegraph.mjs similarity index 100% rename from src/website/tools/profiler-film/films/profiler/flamegraph.mjs rename to src/website/tools/video/films/profiler/flamegraph.mjs diff --git a/src/website/tools/video/films/profiler/render.mjs b/src/website/tools/video/films/profiler/render.mjs new file mode 100644 index 00000000..b683a4df --- /dev/null +++ b/src/website/tools/video/films/profiler/render.mjs @@ -0,0 +1,59 @@ +// Implements [WEB-DESIGN-MEDIA]. Renders the profiler film and the website's profiler media from capture.mjs's +// output: steps film.html frame by frame in headless Chromium, pipes the frames +// to ffmpeg, then writes the site assets (film MP4/WebM + poster, the unedited +// recordings + posters, WebP stills). +// +// node src/website/tools/video/films/profiler/render.mjs +// node src/website/tools/video/films/profiler/render.mjs --preview 2,9.5,24 (stills of those seconds) +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { H264, VP9, ffmpeg, out, poster, publishStills, videos } from '../../kit/encode.mjs'; +import { explode, previewFrames, renderMaster } from '../../kit/frames.mjs'; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const html = path.join(here, 'film.html'); +const POSTER_AT = 25.5; + +/** Each clip's frame count, once exploded into out/film//, and the click cues capture.mjs recorded. */ +function filmData() { + const clip = (name) => ({ + frames: explode(path.join(out, 'clips', `${name}.mp4`), path.join(out, 'film', name)), + cues: JSON.parse(fs.readFileSync(path.join(out, 'clips', `${name}.cues.json`), 'utf8')), + }); + return { cpu: clip('cpu'), memory: clip('memory') }; +} + +async function preview(times) { + const duration = await previewFrames(html, 'FILM_DATA', filmData(), times, path.join(out, 'preview')); + process.stdout.write(`film is ${duration.toFixed(1)}s; previews in out/preview\n`); +} + +/** The site's film: H.264 for reach, VP9 for size, and a poster frame. */ +function publishFilm(master) { + ffmpeg(['-i', master, ...H264, path.join(videos, 'profiler-film.mp4')], 'film mp4'); + ffmpeg(['-i', master, ...VP9, path.join(videos, 'profiler-film.webm')], 'film webm'); + poster(master, POSTER_AT, 'profiler-film'); +} + +/** The unedited recordings: CPU in real time, memory as a 3x time-lapse. */ +function publishRecordings() { + ffmpeg(['-i', path.join(out, 'clips/cpu.mp4'), '-vf', 'scale=1920:-2:flags=lanczos', ...H264, path.join(videos, 'profiler-cpu-recording.mp4')], 'cpu recording'); + ffmpeg(['-i', path.join(out, 'clips/memory.mp4'), '-vf', 'setpts=PTS/3,fps=30,scale=1920:-2:flags=lanczos', ...H264, path.join(videos, 'profiler-memory-timelapse.mp4')], 'memory recording'); + poster(path.join(videos, 'profiler-cpu-recording.mp4'), 16, 'profiler-cpu-recording'); + poster(path.join(videos, 'profiler-memory-timelapse.mp4'), 14, 'profiler-memory-timelapse'); +} + +async function main() { + const flag = process.argv.indexOf('--preview'); + if (flag > 0) return preview(process.argv[flag + 1].split(',').map(Number)); + fs.mkdirSync(videos, { recursive: true }); + const master = path.join(out, 'film-master.mp4'); + const duration = await renderMaster(html, 'FILM_DATA', filmData(), master); + publishFilm(master); + publishRecordings(); + publishStills(path.join(out, 'stills')); + process.stdout.write(`rendered ${duration.toFixed(1)}s film and the profiler media\n`); +} + +await main(); diff --git a/src/website/tools/profiler-film/films/refactoring.mjs b/src/website/tools/video/films/refactoring.mjs similarity index 96% rename from src/website/tools/profiler-film/films/refactoring.mjs rename to src/website/tools/video/films/refactoring.mjs index bc8dd78c..7e841aba 100644 --- a/src/website/tools/profiler-film/films/refactoring.mjs +++ b/src/website/tools/video/films/refactoring.mjs @@ -2,7 +2,7 @@ // (`refactoring`): an F# match completed and a function renamed across files, // then C# fixes that generate a missing method and add a missing using. // -// node src/website/tools/profiler-film/film.mjs refactoring +// node src/website/tools/video/film.mjs refactoring import { LANGUAGE, quickFix, scene } from '../kit/acts/language.mjs'; import { AT_PIPELINE, AT_SESSIONS, missingCase, ready, renameAcrossFiles } from '../kit/acts/shop.mjs'; import { SHOP } from '../kit/set.mjs'; diff --git a/src/website/tools/profiler-film/films/refactoring.narration.json b/src/website/tools/video/films/refactoring.narration.json similarity index 100% rename from src/website/tools/profiler-film/films/refactoring.narration.json rename to src/website/tools/video/films/refactoring.narration.json diff --git a/src/website/tools/hero-netfx-windows.html b/src/website/tools/video/heroes/netfx-windows.html similarity index 100% rename from src/website/tools/hero-netfx-windows.html rename to src/website/tools/video/heroes/netfx-windows.html diff --git a/src/website/tools/profiler-film/kit/acts/cpu.mjs b/src/website/tools/video/kit/acts/cpu.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/acts/cpu.mjs rename to src/website/tools/video/kit/acts/cpu.mjs diff --git a/src/website/tools/profiler-film/kit/acts/explorer.mjs b/src/website/tools/video/kit/acts/explorer.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/acts/explorer.mjs rename to src/website/tools/video/kit/acts/explorer.mjs diff --git a/src/website/tools/profiler-film/kit/acts/language.mjs b/src/website/tools/video/kit/acts/language.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/acts/language.mjs rename to src/website/tools/video/kit/acts/language.mjs diff --git a/src/website/tools/profiler-film/kit/acts/memory.mjs b/src/website/tools/video/kit/acts/memory.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/acts/memory.mjs rename to src/website/tools/video/kit/acts/memory.mjs diff --git a/src/website/tools/profiler-film/kit/acts/shop.mjs b/src/website/tools/video/kit/acts/shop.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/acts/shop.mjs rename to src/website/tools/video/kit/acts/shop.mjs diff --git a/src/website/tools/profiler-film/kit/acts/tour.mjs b/src/website/tools/video/kit/acts/tour.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/acts/tour.mjs rename to src/website/tools/video/kit/acts/tour.mjs diff --git a/src/website/tools/profiler-film/kit/camera.mjs b/src/website/tools/video/kit/camera.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/camera.mjs rename to src/website/tools/video/kit/camera.mjs diff --git a/src/website/tools/profiler-film/kit/code.mjs b/src/website/tools/video/kit/code.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/code.mjs rename to src/website/tools/video/kit/code.mjs diff --git a/src/website/tools/profiler-film/kit/editor.mjs b/src/website/tools/video/kit/editor.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/editor.mjs rename to src/website/tools/video/kit/editor.mjs diff --git a/src/website/tools/profiler-film/kit/encode.mjs b/src/website/tools/video/kit/encode.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/encode.mjs rename to src/website/tools/video/kit/encode.mjs diff --git a/src/website/tools/video/kit/frames.mjs b/src/website/tools/video/kit/frames.mjs new file mode 100644 index 00000000..1ad3c2d5 --- /dev/null +++ b/src/website/tools/video/kit/frames.mjs @@ -0,0 +1,80 @@ +// Implements [WEB-DESIGN-MEDIA]. Composited films are web pages whose every frame +// is a pure function of t: `window.renderFrame(t)` sets the page and resolves once +// its images are decoded. This steps such a page in headless Chromium and pipes +// each frame, losslessly, into a master encode; `explode` turns footage into the +// numbered JPEGs those pages step through. +import { spawn } from 'node:child_process'; +import fs from 'node:fs'; +import path from 'node:path'; +import { chromium } from '@playwright/test'; +import { ffmpeg } from './encode.mjs'; + +export const FPS = 30; +const VIEWPORT = { width: 1920, height: 1080 }; + +/** `video` (optionally `filter`ed) as `dir/00001.jpg` onwards at FPS; returns the frame count. */ +export function explode(video, dir, filter = '') { + fs.rmSync(dir, { recursive: true, force: true }); + fs.mkdirSync(dir, { recursive: true }); + ffmpeg(['-i', video, '-vf', [`fps=${FPS}`, filter].filter(Boolean).join(','), '-q:v', '2', path.join(dir, '%05d.jpg')], path.basename(dir)); + return fs.readdirSync(dir).filter((file) => file.endsWith('.jpg')).length; +} + +/** Open `html` with `data` as `window[global]`; resolves to the page and the length it reports as FILM_DURATION. */ +export async function openFilm(browser, html, global, data) { + const page = await browser.newPage({ viewport: VIEWPORT, deviceScaleFactor: 1 }); + await page.addInitScript(([name, value]) => { + window[name] = value; + }, [global, data]); + await page.goto(`file://${html}`); + await page.evaluate(() => document.fonts.ready); + return { page, duration: await page.evaluate(() => window.FILM_DURATION) }; +} + +/** A lossless H.264 encoder reading PNG frames from its stdin. */ +function encoder(master) { + const args = ['-y', '-loglevel', 'error', '-f', 'image2pipe', '-framerate', String(FPS), '-c:v', 'png', '-i', '-', + '-c:v', 'libx264', '-preset', 'slow', '-crf', '12', '-pix_fmt', 'yuv420p', master]; + const child = spawn('ffmpeg', args, { stdio: ['pipe', 'inherit', 'inherit'] }); + const done = new Promise((resolve, reject) => child.once('exit', (code) => (code === 0 ? resolve() : reject(new Error(`master encode exited ${code}`))))); + return { stdin: child.stdin, done }; +} + +/** Step `page` through `duration` seconds into `master`. */ +async function step(page, duration, master) { + const { stdin, done } = encoder(master); + for (let frame = 0; frame < Math.ceil(duration * FPS); frame++) { + await page.evaluate((t) => window.renderFrame(t), frame / FPS); + if (!stdin.write(await page.screenshot({ type: 'png' }))) await new Promise((resolve) => stdin.once('drain', resolve)); + } + stdin.end(); + await done; +} + +/** Render the film page `html`, given `data` as `window[global]`, into the silent `master`; resolves to its length. */ +export async function renderMaster(html, global, data, master) { + const browser = await chromium.launch(); + try { + const { page, duration } = await openFilm(browser, html, global, data); + await step(page, duration, master); + return duration; + } finally { + await browser.close(); + } +} + +/** PNG stills of the film page at each of `times` into `dir`; resolves to the film's length. */ +export async function previewFrames(html, global, data, times, dir) { + const browser = await chromium.launch(); + try { + const { page, duration } = await openFilm(browser, html, global, data); + fs.mkdirSync(dir, { recursive: true }); + for (const t of times) { + await page.evaluate((at) => window.renderFrame(at), t); + await page.screenshot({ path: path.join(dir, `${t}.png`) }); + } + return duration; + } finally { + await browser.close(); + } +} diff --git a/src/website/tools/profiler-film/kit/overlay.mjs b/src/website/tools/video/kit/overlay.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/overlay.mjs rename to src/website/tools/video/kit/overlay.mjs diff --git a/src/website/tools/profiler-film/kit/scenes.mjs b/src/website/tools/video/kit/scenes.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/scenes.mjs rename to src/website/tools/video/kit/scenes.mjs diff --git a/src/website/tools/profiler-film/kit/screencast.mjs b/src/website/tools/video/kit/screencast.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/screencast.mjs rename to src/website/tools/video/kit/screencast.mjs diff --git a/src/website/tools/profiler-film/kit/set.mjs b/src/website/tools/video/kit/set.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/set.mjs rename to src/website/tools/video/kit/set.mjs diff --git a/src/website/tools/profiler-film/kit/sound/score.mjs b/src/website/tools/video/kit/sound/score.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/sound/score.mjs rename to src/website/tools/video/kit/sound/score.mjs diff --git a/src/website/tools/profiler-film/kit/sound/soundtrack.mjs b/src/website/tools/video/kit/sound/soundtrack.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/sound/soundtrack.mjs rename to src/website/tools/video/kit/sound/soundtrack.mjs diff --git a/src/website/tools/profiler-film/kit/sound/voice.mjs b/src/website/tools/video/kit/sound/voice.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/sound/voice.mjs rename to src/website/tools/video/kit/sound/voice.mjs diff --git a/src/website/tools/profiler-film/kit/workbench.mjs b/src/website/tools/video/kit/workbench.mjs similarity index 100% rename from src/website/tools/profiler-film/kit/workbench.mjs rename to src/website/tools/video/kit/workbench.mjs diff --git a/src/website/tools/profiler-film/package-lock.json b/src/website/tools/video/package-lock.json similarity index 99% rename from src/website/tools/profiler-film/package-lock.json rename to src/website/tools/video/package-lock.json index 4aa01570..d0f1f6a2 100644 --- a/src/website/tools/profiler-film/package-lock.json +++ b/src/website/tools/video/package-lock.json @@ -1,10 +1,10 @@ { - "name": "sharplsp-profiler-film", + "name": "sharplsp-video", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "sharplsp-profiler-film", + "name": "sharplsp-video", "devDependencies": { "kokoro-js": "1.2.1" } diff --git a/src/website/tools/profiler-film/package.json b/src/website/tools/video/package.json similarity index 87% rename from src/website/tools/profiler-film/package.json rename to src/website/tools/video/package.json index 5a9c8d01..9935a0f9 100644 --- a/src/website/tools/profiler-film/package.json +++ b/src/website/tools/video/package.json @@ -1,5 +1,5 @@ { - "name": "sharplsp-profiler-film", + "name": "sharplsp-video", "private": true, "type": "module", "description": "Local tools that shoot and narrate the website's profiler films. Narration runs on this machine; nothing is sent to a speech service.", From 86bcfc21b34a1e8e20deadfd8f175e283eaadff6 Mon Sep 17 00:00:00 2001 From: Christian Findlay <16697547+MelbourneDeveloper@users.noreply.github.com> Date: Tue, 20 Oct 2026 18:14:24 +1100 Subject: [PATCH 08/48] Videos: the figure shortcode names the new video folder --- src/website/video-figure.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/website/video-figure.js b/src/website/video-figure.js index acdaa601..235c4850 100644 --- a/src/website/video-figure.js +++ b/src/website/video-figure.js @@ -7,7 +7,7 @@ // page names a video with `{% video "" %}` and never repeats its markup; files // live at /assets/videos/. beside /assets/videos/-poster.webp // and -card.jpg, and a narrated video's captions at /assets/videos/..vtt. -// The profiler media is shot and published by tools/profiler-film (film.mjs and +// The profiler media is shot and published by tools/video (film.mjs and // films/profiler/render.mjs). The tour is // the Marketplace GIF (assets/images/marketplace/sharplsp-tour.gif) re-encoded // with the same H.264/VP9 settings, because a GIF is eight times the bytes. From f8bce940d2e46057bf2573dcd28efc736b3ee1c6 Mon Sep 17 00:00:00 2001 From: Christian Findlay <16697547+MelbourneDeveloper@users.noreply.github.com> Date: Tue, 20 Oct 2026 18:24:50 +1100 Subject: [PATCH 09/48] Videos: lessons, slide films that teach one feature A lesson is a narrated slide deck (kit/lesson/) around real footage cut from a feature's published walkthrough, so no editor frame is mocked. Slides hold until their lines are spoken, and each item appears as its line starts. The sound kit is shared by both kinds of film: a script now picks its voice speed, its pacing and its score, and kit/sound/drive.mjs is a new energetic score for the lessons. kit/publish.mjs is the one place films are encoded and narrated. First lesson: refactoring-lesson (Code Actions), in film.mjs. --- src/website/tools/video/film.mjs | 38 ++- .../tools/video/films/refactoring-lesson.mjs | 145 +++++++++ .../films/refactoring-lesson.narration.json | 283 ++++++++++++++++++ src/website/tools/video/kit/lesson/deck.html | 131 ++++++++ src/website/tools/video/kit/lesson/deck.js | 121 ++++++++ src/website/tools/video/kit/lesson/lesson.mjs | 71 +++++ src/website/tools/video/kit/publish.mjs | 35 +++ src/website/tools/video/kit/scenes.mjs | 38 +-- src/website/tools/video/kit/sound/drive.mjs | 119 ++++++++ src/website/tools/video/kit/sound/score.mjs | 21 +- .../tools/video/kit/sound/soundtrack.mjs | 34 ++- src/website/tools/video/kit/sound/voice.mjs | 9 +- 12 files changed, 981 insertions(+), 64 deletions(-) create mode 100644 src/website/tools/video/films/refactoring-lesson.mjs create mode 100644 src/website/tools/video/films/refactoring-lesson.narration.json create mode 100644 src/website/tools/video/kit/lesson/deck.html create mode 100644 src/website/tools/video/kit/lesson/deck.js create mode 100644 src/website/tools/video/kit/lesson/lesson.mjs create mode 100644 src/website/tools/video/kit/publish.mjs create mode 100644 src/website/tools/video/kit/sound/drive.mjs diff --git a/src/website/tools/video/film.mjs b/src/website/tools/video/film.mjs index 332f136c..e7a2828b 100644 --- a/src/website/tools/video/film.mjs +++ b/src/website/tools/video/film.mjs @@ -1,9 +1,11 @@ -// Implements [WEB-DESIGN-MEDIA]. Shoots and publishes one walkthrough film from -// films/.mjs. See README.md. +// Implements [WEB-DESIGN-MEDIA]. Shoots and publishes one film from films/.mjs: +// a walkthrough (scenes shot in a real editor) or a lesson (slides around footage +// cut from a published walkthrough). See README.md. // // make _build-vsix VSIX_PREBUILT=1 // node src/website/tools/video/film.mjs (shoot, then publish) // node src/website/tools/video/film.mjs --publish (publish the last shoot) +// node src/website/tools/video/film.mjs --preview 2,30 (a lesson's stills at those seconds) // // A shoot lands in out// (gitignored); publishing writes the site's video, // poster, captions and stills under src/website/src/assets. @@ -11,21 +13,37 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { out as filmsOut, publishStills } from './kit/encode.mjs'; +import { previewLesson, publishLesson } from './kit/lesson/lesson.mjs'; import { publishWalkthrough, shootWalkthrough } from './kit/scenes.mjs'; const films = path.join(path.dirname(fileURLToPath(import.meta.url)), 'films'); const available = fs.readdirSync(films).filter((file) => file.endsWith('.mjs')).map((file) => file.replace(/\.mjs$/, '')); const [id] = process.argv.slice(2).filter((arg) => !arg.startsWith('--')); -if (!available.includes(id)) throw new Error(`usage: film.mjs <${available.join('|')}> [--publish]`); +if (!available.includes(id)) throw new Error(`usage: film.mjs <${available.join('|')}> [--publish | --preview ]`); const film = (await import(path.join(films, `${id}.mjs`))).default; const out = path.join(filmsOut, id); const narration = film.narration && JSON.parse(fs.readFileSync(path.join(films, film.narration), 'utf8')); -if (!process.argv.includes('--publish')) await shootWalkthrough({ demo: film.demo, out, scenes: film.scenes, settings: film.settings }); -if (fs.existsSync(path.join(out, 'stills'))) publishStills(path.join(out, 'stills'), film.stillsFolder); -// A film of stills alone has no clips to cut. -if (film.scenes.some((scene) => scene.clip)) { - const length = await publishWalkthrough({ name: film.name, out, scenes: film.scenes, posterAt: film.poster, narration }); - process.stdout.write(`${film.name}: ${length.toFixed(1)}s published\n`); -} else process.stdout.write(`${film.name}: stills published\n`); +/** A lesson renders from its slides: `--preview` writes stills at the given seconds, otherwise it publishes. */ +async function lesson() { + const preview = process.argv.indexOf('--preview'); + const plan = { ...film.lesson, name: film.name, poster: film.poster, out }; + if (preview < 0) return `${film.name}: ${(await publishLesson(plan, narration)).toFixed(1)}s published`; + const times = process.argv[preview + 1].split(',').map(Number); + return `${film.name}: ${(await previewLesson(plan, narration, times)).toFixed(1)}s drafted; stills in out/${id}/preview`; +} + +/** A walkthrough shoots its scenes, then cuts and publishes them. */ +async function walkthrough() { + if (!process.argv.includes('--publish')) await shootWalkthrough({ demo: film.demo, out, scenes: film.scenes, settings: film.settings }); + if (fs.existsSync(path.join(out, 'stills'))) publishStills(path.join(out, 'stills'), film.stillsFolder); + // A film of stills alone has no clips to cut. + if (film.scenes.some((scene) => scene.clip)) { + const length = await publishWalkthrough({ name: film.name, out, scenes: film.scenes, posterAt: film.poster, narration }); + process.stdout.write(`${film.name}: ${length.toFixed(1)}s published\n`); + } else process.stdout.write(`${film.name}: stills published\n`); +} + +if (film.lesson) process.stdout.write(`${await lesson()}\n`); +else await walkthrough(); diff --git a/src/website/tools/video/films/refactoring-lesson.mjs b/src/website/tools/video/films/refactoring-lesson.mjs new file mode 100644 index 00000000..1bda2245 --- /dev/null +++ b/src/website/tools/video/films/refactoring-lesson.mjs @@ -0,0 +1,145 @@ +// Implements [WEB-DESIGN-MEDIA]. The "Refactoring & Code Actions" lesson +// (`refactoring-lesson`): the shortcut, where actions come from, an F# match +// completed and the F# fixes by diagnostic, rename across files, C# fixes that +// generate a method and add a using, what happens underneath, and what is not a +// code action. Its footage is cut from the `refactoring` walkthrough. +// +// node src/website/tools/video/film.mjs refactoring-lesson +// node src/website/tools/video/film.mjs refactoring-lesson --preview 2,20,60 +// +// Each clip is a crop of the walkthrough's 1920x1200 editor: the code and its +// menus, without the step caption the walkthrough recorded under them. +const FSHARP = [430, 108, 1100, 640]; +const RENAME = [430, 108, 1250, 727]; +const CSHARP = [430, 170, 1100, 640]; +const clip = (from, to, crop, label, speed = 1) => ({ video: 'refactoring', from, to, crop, label, speed }); + +export default { + name: 'refactoring-lesson', + narration: 'refactoring-lesson.narration.json', + poster: 32, + lesson: { + series: 'Lesson · Code actions', + slides: [ + { + id: 'intro', layout: 'title', kicker: 'Lesson · Refactoring & Code Actions', + title: 'Turn problems
into code.', + sub: 'Fix code, generate code and rename across files, in F# and C#: what to press, what you get, and what happens underneath.', + chips: ['macOS · Linux · Windows', 'F# + C#', 'VS Code', 'Free · MIT'], + }, + { + id: 'shortcut', layout: 'keys', kicker: 'Step 1 · The shortcut', heading: 'Every action starts from one shortcut', + keys: [ + { os: 'macOS', caps: ['⌘', '+', '.'], hot: true, line: 0 }, + { os: 'Windows · Linux', caps: ['Ctrl', '+', '.'], line: 1 }, + { os: 'Or click', caps: ['💡'], line: 2 }, + ], + sub: 'The menu lists only what applies to your cursor, your selection or the diagnostic under it.', subLine: 3, + }, + { + id: 'context', layout: 'points', kicker: 'Step 2 · Where actions come from', heading: 'Actions are context-dependent', + rows: [ + { k: 'A diagnostic', v: 'A warning or error asks for its own fix', w: 'Quick fix', line: 1 }, + { k: 'The cursor', v: 'A type or member you can reshape', w: 'Refactor', line: 2 }, + { k: 'A selection', v: 'Refactorings that work on the code you highlight', w: 'Refactor', line: 3 }, + { k: 'A blank line', v: 'An empty menu. SharpLsp never guesses', w: 'Nothing', line: 4 }, + ], + }, + { + id: 'fsharp', layout: 'footage', kicker: 'Step 3 · F# first', heading: 'Complete an F# match', + footage: clip(0, 13.7, FSHARP, 'Sessions.fs · FS0025: incomplete match', 2), + notes: [ + { text: 'describe matches on stage, but misses a union case', line: 0 }, + { text: 'The compiler warns: FS0025, incomplete pattern match', line: 1 }, + { text: '⌘. → Generate 1 missing union case(s)', line: 2 }, + { text: 'Or Add wildcard case for a catch-all | _ ->', line: 3 }, + ], + }, + { + id: 'fsharp-code', layout: 'code', kicker: 'Step 3 · What it wrote', heading: 'Before and after', + panes: [ + { label: 'Before · FS0025', line: 0, code: [ + { text: 'let describe stage =' }, { text: ' match stage with', mark: 'warn' }, { text: ' | Browsing -> "still browsing"' }, + ] }, + { label: 'After · Generate missing case', line: 0, code: [ + { text: 'let describe stage =' }, { text: ' match stage with' }, { text: ' | Browsing -> "still browsing"' }, + { text: ' | CheckedOut _ -> failwith "todo"', mark: 'add' }, + ] }, + ], + caption: 'The compiler knows every case of the union, so the arm is exact. You write the body.', captionLine: 1, + }, + { + id: 'fsharp-fixes', layout: 'cards', kicker: 'Step 4 · The F# toolkit', heading: 'F# quick fixes, by diagnostic', + cards: [ + { code: 'FS0025', text: 'Add a wildcard match arm', line: 0 }, + { code: 'FS0026', text: 'Remove a redundant pattern', line: 0 }, + { code: 'FS0001', text: 'Insert a known conversion', line: 0 }, + { code: 'FS0039', text: 'Add the open that resolves a name', line: 1 }, + { code: 'FS1182', text: 'Prefix an unused binding with _', line: 1 }, + { code: 'FS0020', text: 'Pipe a discarded value to ignore', line: 1 }, + { code: 'match', text: 'Generate missing union cases', line: 2 }, + { code: '{ record }', text: 'Generate missing fields', line: 2 }, + { code: 'interface', text: 'Generate member stubs', line: 2 }, + ], + }, + { + id: 'rename', layout: 'footage', kicker: 'Step 5 · Rename', heading: 'Rename is F2, not a code action', + footage: clip(13.75, 35.3, RENAME, 'Sessions.fs → Program.fs · Rename Symbol'), + notes: [ + { text: 'Cursor on remember, press F2', line: 0 }, + { text: 'Type rememberOrder, press Enter', line: 1 }, + { text: 'The call in Program.fs follows', line: 2 }, + { text: 'C#: Roslyn\'s solution. F#: the loaded F# project', line: 3 }, + ], + }, + { + id: 'generate', layout: 'footage', kicker: 'Step 6 · C#', heading: 'Call it first, generate it second', + footage: clip(35.35, 59.7, CSHARP, 'CheckoutPipeline.cs · Generate method'), + notes: [ + { text: 'Write the call you wish existed: Receipt(invoice)', line: 0 }, + { text: 'It doesn\'t exist yet, so it\'s an error', line: 1 }, + { text: '⌘. → Generate method', line: 2 }, + { text: 'Roslyn writes the stub, typed from your call', line: 3 }, + ], + }, + { + id: 'using', layout: 'footage', kicker: 'Step 7 · C#', heading: 'Add the missing using', + footage: clip(59.75, 87.1, CSHARP, 'CheckoutPipeline.cs · Add using'), + notes: [ + { text: 'Use StringBuilder without its namespace', line: 0 }, + { text: '⌘. offers using System.Text; first', line: 1 }, + { text: 'Or qualify it in place, or generate a class', line: 2 }, + { text: 'Roslyn\'s own fixes, bundled with SharpLsp', line: 3 }, + ], + }, + { + id: 'under', layout: 'flow', kicker: 'Under the hood', heading: 'Two requests: list, then resolve', + stages: [ + { title: 'Ask', text: 'The editor sends textDocument/codeAction for the cursor or selection', line: 0 }, + { title: 'List', text: 'Roslyn (C#) or the F# compiler (F#) returns titles only, so the menu is quick', line: 1 }, + { title: 'Resolve', text: 'Pick one: only then does codeAction/resolve compute its edits', line: 2 }, + { title: 'Apply', text: 'One workspace edit, which can change several files', line: 3 }, + ], + sub: 'Stale action, or a restarted sidecar? Resolve returns no edit. It never guesses.', subLine: 4, + }, + { + id: 'separate', layout: 'points', kicker: 'Good to know', heading: 'Formatting and sorting are separate', + rows: [ + { k: 'Format C#', v: 'Use CSharpier', w: 'Not an LSP format', line: 1 }, + { k: 'Format F#', v: 'Use Fantomas', w: 'Not an LSP format', line: 1 }, + { k: 'Sort Members', v: 'Right-click a C# type in the Solution Explorer', w: 'Its own command', line: 2 }, + ], + }, + { + id: 'recap', layout: 'recap', kicker: 'Recap', heading: 'You just learned', + items: [ + { text: '⌘. or Ctrl . opens every action that applies', line: 0 }, + { text: 'F# fixes follow compiler diagnostics, and write whole match cases', line: 1 }, + { text: 'F2 renames across files, in F# and C#', line: 2 }, + { text: 'In C#, call first and generate second', line: 3 }, + ], + url: 'sharplsp.dev/docs/refactoring', urlLine: 4, + }, + ], + }, +}; diff --git a/src/website/tools/video/films/refactoring-lesson.narration.json b/src/website/tools/video/films/refactoring-lesson.narration.json new file mode 100644 index 00000000..66d5bb71 --- /dev/null +++ b/src/website/tools/video/films/refactoring-lesson.narration.json @@ -0,0 +1,283 @@ +{ + "voice": "af_bella", + "speed": 1.12, + "score": "drive", + "pacing": { "opening": 0.9, "lead": 0.25, "gap": 0.22, "tail": 0.35, "hold": 0.25, "closing": 2.4 }, + "say": { + "SharpLsp": "Sharp L S P", + "FS0025": "F S zero zero twenty-five", + "Program.fs": "Program dot F S", + "System.Text": "System dot Text", + "CSharpier": "See Sharpier", + "F#": "F sharp", + "C#": "C sharp", + "F2": "F two" + }, + "music": { "en": "[Upbeat electronic music]", "ja": "[アップテンポな電子音楽]", "zh": "[轻快的电子音乐]" }, + "lines": [ + { + "scene": "intro", + "en": "Welcome to a quick lesson on code actions in SharpLsp! In the next few minutes, you'll fix code, generate code, and rename across files, in F# and C#, on any OS.", + "ja": "SharpLsp のコードアクションのクイックレッスンへようこそ!数分で、コードの修正、コードの生成、ファイルをまたいだ名前の変更を、F# と C# で、どの OS でも学べます。", + "zh": "欢迎来到 SharpLsp 代码操作快速课程!接下来几分钟,你将学会在任何系统上用 F# 和 C# 修复代码、生成代码,以及跨文件重命名。" + }, + { + "scene": "shortcut", + "en": "First, the one shortcut you need. On a Mac, press Command dot.", + "ja": "まずは、覚えるべきショートカットはひとつだけ。Mac では Command+. を押します。", + "zh": "首先,你只需要记住一个快捷键。在 Mac 上,按 Command+.。" + }, + { + "scene": "shortcut", + "en": "On Windows and Linux, it's Control dot.", + "ja": "Windows と Linux では Ctrl+. です。", + "zh": "在 Windows 和 Linux 上,是 Ctrl+.。" + }, + { + "scene": "shortcut", + "en": "Or just click the lightbulb.", + "ja": "または電球アイコンをクリックするだけです。", + "zh": "或者直接点击灯泡图标。" + }, + { + "scene": "shortcut", + "en": "Either way, the menu only lists actions that apply to your cursor, your selection, or the diagnostic under it.", + "ja": "どの方法でも、メニューにはカーソル、選択範囲、またはその下の診断に当てはまるアクションだけが表示されます。", + "zh": "无论哪种方式,菜单只会列出适用于光标、选区或其下诊断的操作。" + }, + { + "scene": "context", + "en": "So where do actions come from? Three places.", + "ja": "では、アクションはどこから来るのでしょう?三つあります。", + "zh": "那么,这些操作从哪里来?有三个来源。" + }, + { + "scene": "context", + "en": "A diagnostic: a warning or an error asks for its own fix.", + "ja": "診断:警告やエラーが、それ自身の修正を求めます。", + "zh": "诊断:警告或错误会提供它自己的修复。" + }, + { + "scene": "context", + "en": "The cursor: a type or member you can reshape.", + "ja": "カーソル:作り変えられる型やメンバー。", + "zh": "光标:可以重塑的类型或成员。" + }, + { + "scene": "context", + "en": "And a selection: refactorings that work on the code you highlight.", + "ja": "そして選択範囲:選択したコードに働くリファクタリングです。", + "zh": "还有选区:作用于你所选代码的重构。" + }, + { + "scene": "context", + "en": "On a blank line, you get an empty menu. SharpLsp never guesses.", + "ja": "空行では、メニューは空です。SharpLsp は推測しません。", + "zh": "在空行上,菜单是空的。SharpLsp 从不瞎猜。" + }, + { + "scene": "fsharp", + "en": "Let's start with F#. This describe function matches on a stage, but it's missing a union case.", + "ja": "F# から始めましょう。この describe 関数は stage で match していますが、共用体ケースがひとつ足りません。", + "zh": "我们从 F# 开始。这个 describe 函数对 stage 做 match,但漏了一个联合用例。" + }, + { + "scene": "fsharp", + "en": "The compiler flags it with warning FS0025: an incomplete pattern match.", + "ja": "コンパイラーは警告 FS0025、不完全なパターンマッチとして知らせます。", + "zh": "编译器用警告 FS0025 标出它:模式匹配不完整。" + }, + { + "scene": "fsharp", + "en": "Press Command dot, pick Generate missing union case, and SharpLsp writes the arm for you.", + "ja": "Command+. を押して「Generate missing union case」を選べば、SharpLsp がその分岐を書いてくれます。", + "zh": "按 Command+.,选择 Generate missing union case,SharpLsp 就会替你写出这个分支。" + }, + { + "scene": "fsharp", + "en": "Prefer a catch-all? Add wildcard case is right there too.", + "ja": "すべてを受け止めたいなら、「Add wildcard case」もすぐ隣にあります。", + "zh": "想要兜底分支?Add wildcard case 也就在旁边。" + }, + { + "scene": "fsharp-code", + "en": "Here's the result. The new arm matches exactly the case that was missing,", + "ja": "これが結果です。新しい分岐は、足りなかったケースにぴったり一致します。", + "zh": "这是结果。新分支恰好匹配了缺失的那个用例," + }, + { + "scene": "fsharp-code", + "en": "because the F# compiler knows every case of the union. You just write the body.", + "ja": "F# コンパイラーが共用体のすべてのケースを知っているからです。あなたは本体を書くだけです。", + "zh": "因为 F# 编译器知道联合类型的每一个用例。你只需要写函数体。" + }, + { + "scene": "fsharp-fixes", + "en": "That's one fix from a whole F# toolkit, each tied to a compiler diagnostic.", + "ja": "これは F# の修正ツールキットのひとつにすぎず、どれもコンパイラーの診断に結びついています。", + "zh": "这只是整套 F# 修复工具中的一个,每一个都对应一条编译器诊断。" + }, + { + "scene": "fsharp-fixes", + "en": "Unresolved name? Add the open. Unused binding? Prefix it with an underscore. A discarded value? Pipe it to ignore.", + "ja": "名前が解決できない?open を追加。未使用の束縛?アンダースコアを付ける。捨てられた値?ignore にパイプする。", + "zh": "名字无法解析?添加 open。绑定未使用?加上下划线前缀。值被丢弃?用管道传给 ignore。" + }, + { + "scene": "fsharp-fixes", + "en": "And beyond matches, SharpLsp generates missing record fields and interface member stubs.", + "ja": "match 以外にも、SharpLsp は足りないレコードのフィールドや、インターフェイスのメンバーのスタブを生成します。", + "zh": "除了 match,SharpLsp 还能生成缺失的记录字段和接口成员存根。" + }, + { + "scene": "rename", + "en": "Renaming is separate from code actions. Put the cursor on a symbol and press F2.", + "ja": "名前の変更はコードアクションとは別です。シンボルにカーソルを置いて F2 を押します。", + "zh": "重命名和代码操作是分开的。把光标放在符号上,按 F2。" + }, + { + "scene": "rename", + "en": "Type the new name and hit enter.", + "ja": "新しい名前を入力して Enter を押します。", + "zh": "输入新名字,然后按回车。" + }, + { + "scene": "rename", + "en": "Every reference follows, even in other files. Here, the call in Program.fs updates too.", + "ja": "すべての参照が追従します。別のファイルでもです。ここでは Program.fs の呼び出しも更新されます。", + "zh": "所有引用都会跟着改,即使在其他文件里。这里,Program.fs 中的调用也更新了。" + }, + { + "scene": "rename", + "en": "In C#, rename runs on Roslyn's loaded solution. In F#, on the loaded F# project.", + "ja": "C# では Roslyn が読み込んだソリューションで、F# では読み込んだ F# プロジェクトで名前を変更します。", + "zh": "在 C# 中,重命名基于 Roslyn 加载的解决方案;在 F# 中,基于已加载的 F# 项目。" + }, + { + "scene": "generate", + "en": "Now C#. Here's a favourite workflow: write the call you wish existed. Receipt, of invoice.", + "ja": "次は C# です。お気に入りのやり方:あったらいいなと思う呼び出しを書きます。Receipt(invoice) です。", + "zh": "现在看 C#。一个很受欢迎的做法:先写出你希望存在的调用。比如 Receipt(invoice)。" + }, + { + "scene": "generate", + "en": "It doesn't exist yet, so the compiler reports an error.", + "ja": "まだ存在しないので、コンパイラーはエラーを報告します。", + "zh": "它还不存在,所以编译器报错。" + }, + { + "scene": "generate", + "en": "Command dot. Generate method.", + "ja": "Command+.、「Generate method」。", + "zh": "Command+.,选择 Generate method。" + }, + { + "scene": "generate", + "en": "Roslyn writes the stub, and takes the parameter type from your call.", + "ja": "Roslyn がスタブを書き、パラメーターの型は呼び出しから決めます。", + "zh": "Roslyn 会写出存根,并根据你的调用确定参数类型。" + }, + { + "scene": "using", + "en": "Next, use a type without importing its namespace. StringBuilder, say.", + "ja": "次に、名前空間をインポートせずに型を使います。たとえば StringBuilder。", + "zh": "接下来,在没有导入命名空间的情况下使用一个类型,比如 StringBuilder。" + }, + { + "scene": "using", + "en": "Quick Fix puts using System.Text right at the top.", + "ja": "クイックフィックスは using System.Text をいちばん上に出します。", + "zh": "快速修复会把 using System.Text 放在最上面。" + }, + { + "scene": "using", + "en": "You could also qualify it in place, or even generate a new class.", + "ja": "その場で完全修飾したり、新しいクラスを生成したりもできます。", + "zh": "你也可以就地写出完全限定名,甚至生成一个新类。" + }, + { + "scene": "using", + "en": "These come straight from Roslyn's own code fix providers, bundled with SharpLsp.", + "ja": "これらは SharpLsp に同梱された Roslyn 自身のコード修正プロバイダーから直接来ています。", + "zh": "这些都直接来自 SharpLsp 内置的 Roslyn 代码修复提供程序。" + }, + { + "scene": "under", + "en": "So what's happening underneath? Your editor asks for code actions at the cursor.", + "ja": "では、裏で何が起きているのでしょう?エディターがカーソル位置のコードアクションを問い合わせます。", + "zh": "那么底层发生了什么?编辑器会请求光标处的代码操作。" + }, + { + "scene": "under", + "en": "Roslyn, or the F# compiler, sends back a list of titles. That keeps the menu fast.", + "ja": "Roslyn または F# コンパイラーがタイトルの一覧を返します。だからメニューは速いのです。", + "zh": "Roslyn 或 F# 编译器返回一个标题列表,这让菜单保持快速。" + }, + { + "scene": "under", + "en": "Only when you pick one does SharpLsp resolve it and compute the edits.", + "ja": "ひとつ選んだときに初めて、SharpLsp がそれを解決して編集を計算します。", + "zh": "只有当你选中一项时,SharpLsp 才会解析它并计算编辑。" + }, + { + "scene": "under", + "en": "The result is one workspace edit, which can touch several files.", + "ja": "結果はひとつのワークスペース編集で、複数のファイルに及ぶこともあります。", + "zh": "结果是一个工作区编辑,可以同时修改多个文件。" + }, + { + "scene": "under", + "en": "And if an action has gone stale, you get no edit, never a guess.", + "ja": "そしてアクションが古くなっていたら、編集は返りません。推測はしません。", + "zh": "如果某个操作已经过时,你得到的是没有编辑,而绝不是瞎猜。" + }, + { + "scene": "separate", + "en": "Two things that aren't code actions.", + "ja": "コードアクションではないものが二つあります。", + "zh": "有两样东西不属于代码操作。" + }, + { + "scene": "separate", + "en": "SharpLsp doesn't format your code. Use CSharpier for C#, and Fantomas for F#.", + "ja": "SharpLsp はコードを整形しません。C# には CSharpier、F# には Fantomas を使ってください。", + "zh": "SharpLsp 不负责格式化代码。C# 用 CSharpier,F# 用 Fantomas。" + }, + { + "scene": "separate", + "en": "And Sort Members is its own command. Right-click a C# type in the Solution Explorer to reorder its members.", + "ja": "そして Sort Members は独立したコマンドです。ソリューションエクスプローラーで C# の型を右クリックすると、メンバーを並べ替えられます。", + "zh": "Sort Members 则是一个独立命令。在解决方案资源管理器中右键点击一个 C# 类型,即可重新排列它的成员。" + }, + { + "scene": "recap", + "en": "Let's recap. Command dot, or Control dot, opens every action that applies.", + "ja": "おさらいしましょう。Command+. または Ctrl+. で、当てはまるすべてのアクションが開きます。", + "zh": "来回顾一下。Command+. 或 Ctrl+. 会打开所有适用的操作。" + }, + { + "scene": "recap", + "en": "F# fixes follow the compiler's diagnostics, and they can write whole match cases.", + "ja": "F# の修正はコンパイラーの診断に従い、match のケースを丸ごと書けます。", + "zh": "F# 修复跟随编译器诊断,还能写出完整的 match 用例。" + }, + { + "scene": "recap", + "en": "F2 renames across files.", + "ja": "F2 でファイルをまたいで名前を変更できます。", + "zh": "F2 可以跨文件重命名。" + }, + { + "scene": "recap", + "en": "And in C#, you can call first, and generate second.", + "ja": "そして C# では、先に呼び出しを書き、あとから生成できます。", + "zh": "在 C# 中,你可以先写调用,再生成方法。" + }, + { + "scene": "recap", + "en": "The full lesson is in the SharpLsp docs. Now go fix some code!", + "ja": "レッスンの全文は SharpLsp のドキュメントにあります。さあ、コードを直しに行きましょう!", + "zh": "完整课程在 SharpLsp 文档里。现在就去修代码吧!" + } + ] +} diff --git a/src/website/tools/video/kit/lesson/deck.html b/src/website/tools/video/kit/lesson/deck.html new file mode 100644 index 00000000..f432d544 --- /dev/null +++ b/src/website/tools/video/kit/lesson/deck.html @@ -0,0 +1,131 @@ + + + + +SharpLsp lesson + + + + +
+
+
+
SharpLsp
+
+
+ + + diff --git a/src/website/tools/video/kit/lesson/deck.js b/src/website/tools/video/kit/lesson/deck.js new file mode 100644 index 00000000..31ac1ccb --- /dev/null +++ b/src/website/tools/video/kit/lesson/deck.js @@ -0,0 +1,121 @@ +// Implements [WEB-DESIGN-MEDIA]. A lesson's slides, drawn from t alone. LESSON +// (injected by lesson.mjs) holds each slide's content and its timing: when it +// starts and ends, when each of its narration lines starts, and the real +// footage it plays. A slide's items appear as the line that names them is spoken. +'use strict'; + +const LESSON = window.LESSON; +const FPS = 30; +const $ = (id) => document.getElementById(id); +const clamp = (v, lo = 0, hi = 1) => Math.min(hi, Math.max(lo, v)); +const ease = { + out: (p) => 1 - (1 - p) ** 3, + back: (p) => 1 + 2.4 * (p - 1) ** 3 + 1.4 * (p - 1) ** 2, +}; +const ENTER = 0.42; +const EXIT = 0.28; +const REVEAL = 0.5; + +/** The time an item appears: its line's start (or just after the cut), cascading by its `index` among that line's items. */ +const cue = (slide, line, index) => (slide.lines[line] ?? slide.start + 0.35) + 0.12 * index; +/** Each item's place among the items its own line reveals. */ +const ranks = (list) => list.map((item, i) => list.slice(0, i).filter((other) => other.line === item.line).length); +const at = (slide, line, index) => `class="item" data-at="${cue(slide, line, index).toFixed(3)}"`; +const heading = (slide) => + `
${slide.kicker ?? ''}

${slide.heading ?? ''}

`; + +const layouts = { + title: (s) => `
${s.kicker}
+

${s.title}

+

${s.sub}

+
${s.chips.map((chip, i) => `
${chip}
`).join('')}
`, + points: (s) => `${heading(s)}${s.sub ? `

${s.sub}

` : ''} +
${s.rows.map((r, i) => `
${r.k}${r.v}${r.w ?? ''}
`).join('')}
`, + keys: (s) => `${heading(s)}
${s.keys.map((k, i) => `
+
${k.os}
${k.caps.map((c) => (c === '+' ? '+' : `
${c}
`)).join('')}
`).join('')}
+ ${s.sub ? `

${s.sub}

` : ''}`, + footage: (s) => `${heading(s)}
${s.footage.label}Real footage · VS Code
+ ${s.footage.speed > 1 ? `
${s.footage.speed}× speed
` : ''}
+
${s.notes.map((n, i) => `
${i + 1}${n.text}
`).join('')}
`, + cards: (s) => `${heading(s)}
${s.cards.map((c, i) => `
${c.code}

${c.text}

`).join('')}
`, + code: (s) => `${heading(s)}
${s.panes.map((p, i) => `
${p.label}
+
${p.code.map((l) => `${l.text || ' '}
`).join('')}
`).join('')} + ${s.caption ? `

${s.caption}

` : ''}`, + flow: (s) => `${heading(s)}
${s.stages.map((g, i) => `
${String(i + 1).padStart(2, '0')}

${g.title}

${g.text}

`).join('')}
+ ${s.sub ? `

${s.sub}

` : ''}`, + recap: (s) => `${heading(s)}
${s.items.map((r, i) => `
${i + 1}${r.text}
`).join('')}
+
${s.url}
`, +}; + +/** Build every slide once; renderFrame only moves and shows them. */ +function build() { + $('logo').src = LESSON.logo; + $('series').textContent = LESSON.series; + for (const slide of LESSON.slides) { + const node = document.createElement('section'); + node.className = `slide ${slide.layout}-slide`; + node.innerHTML = layouts[slide.layout](slide); + $('slides').append(node); + slide.node = node; + slide.items = [...node.querySelectorAll('.item')].map((el) => ({ el, at: Number(el.dataset.at) })); + slide.frame = node.querySelector('.frame'); + } + for (const slide of LESSON.slides.slice(1)) $('progress').insertAdjacentHTML('beforeend', ``); +} + +/** The slide's own entrance and exit: in from the right, out to the left. */ +function place(slide, t) { + const shown = t >= slide.start && t < slide.end; + slide.node.style.visibility = shown ? 'visible' : 'hidden'; + if (!shown) return false; + const enter = ease.out(clamp((t - slide.start) / ENTER)); + const exit = slide === LESSON.slides.at(-1) ? 0 : ease.out(clamp((t - (slide.end - EXIT)) / EXIT)); + slide.node.style.opacity = String(Math.min(enter, 1 - exit)); + slide.node.style.transform = `translateX(${(1 - enter) * 90 - exit * 70}px)`; + return true; +} + +/** Each item springs up as its line starts; a heading wipes in left to right. */ +function reveal(slide, t) { + for (const { el, at: start } of slide.items) { + const p = clamp((t - start) / REVEAL); + el.style.opacity = String(clamp((t - start) / (REVEAL / 2))); + el.style.transform = `translateY(${(1 - ease.back(p)) * 34}px)`; + if (el.classList.contains('wipe')) el.style.clipPath = `inset(-20% ${(1 - ease.out(p)) * 100}% -20% 0)`; + } +} + +const pending = []; + +/** The footage frame for t: real time from the slide's cut plus its delay, held on its last frame. */ +function footage(slide, t) { + if (!slide.frame) return; + const { base, frames, delay } = slide.footage; + const index = clamp(Math.floor((t - slide.start - delay) * FPS) + 1, 1, frames); + const src = `${base}/${String(index).padStart(5, '0')}.jpg`; + if (slide.frame.dataset.src === src) return; + slide.frame.dataset.src = src; + slide.frame.src = src; + pending.push(slide.frame.decode().catch(() => undefined)); +} + +/** The glow breathes on the score's beat while the drums play. */ +function pulse(t) { + const playing = t >= LESSON.drums && t < LESSON.resolve; + const kick = playing ? Math.exp(-((t - LESSON.drums) % LESSON.beat) / 0.16) : 0; + $('glow').style.opacity = String(0.62 + 0.38 * kick); + $('glow').style.transform = `scale(${1 + 0.035 * kick})`; +} + +window.FILM_DURATION = LESSON.duration; +build(); + +window.renderFrame = (t) => { + pending.length = 0; + const index = LESSON.slides.findIndex((slide) => place(slide, t)); + for (const slide of LESSON.slides) if (slide.node.style.visibility === 'visible') reveal(slide, t), footage(slide, t); + pulse(t); + $('fill').style.width = `${(t / LESSON.duration) * 100}%`; + $('count').textContent = `${String(index + 1).padStart(2, '0')} / ${String(LESSON.slides.length).padStart(2, '0')}`; + return Promise.all(pending).then(() => new Promise((resolve) => requestAnimationFrame(() => resolve()))); +}; diff --git a/src/website/tools/video/kit/lesson/lesson.mjs b/src/website/tools/video/kit/lesson/lesson.mjs new file mode 100644 index 00000000..ec7ecc3b --- /dev/null +++ b/src/website/tools/video/kit/lesson/lesson.mjs @@ -0,0 +1,71 @@ +// Implements [WEB-DESIGN-MEDIA]. A lesson is a narrated slide film that teaches one +// feature end to end. Its slides are data (deck.js draws them); its footage is cut +// from the feature's published walkthrough, so every editor frame it shows is the +// real extension, never a mock-up. Each slide holds until its lines are spoken, +// and its items appear as the line that names them starts. +import path from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { poster, videos } from '../encode.mjs'; +import { FPS, explode, previewFrames, renderMaster } from '../frames.mjs'; +import { narrated } from '../publish.mjs'; +import { drive } from '../sound/drive.mjs'; +import { timeline } from '../sound/soundtrack.mjs'; +import { pacingOf } from '../sound/voice.mjs'; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const DECK = path.join(here, 'deck.html'); +const LOGO = pathToFileURL(path.resolve(here, '../../../../src/assets/images/sharplsp-logo.svg')).href; +/** A slide with no footage is on screen at least this long; footage starts this long after its cut, and holds this long after it ends. */ +const SLIDE = { least: 1.2, delay: 0.5, after: 0.6 }; +/** Spoken words a second, for a draft timed without speaking. */ +const DRAFT_RATE = 3; + +/** `{ video, from, to, crop: [x, y, w, h], speed, label }`, cut from `