port(vscode-extension): rewrite extension.ts as extension.affine (affinescript#64)#11
Merged
Merged
Conversation
…inescript#64)
Closes the my-lang side of affinescript#64 (port external VS Code
extensions to .affine). Unblock condition affinescript#35 (Node-target
codegen + stdlib/Vscode.affine + stdlib/VscodeLanguageClient.affine
bindings) has landed.
Layout:
- src/extension.affine AffineScript source-of-truth
- src/affine-vscode-adapter.cjs Vendored JS adapter (copy of
affinescript:packages/affine-vscode/mod.js,
CJS form). Update when upstream changes.
- src/index.cjs Runtime entry point. Installs
`extraImports` on the wasm shim so the
AffineScript extern bindings resolve to
real vscode/lc API calls before activate.
- out/extension.cjs Generated by `npm run compile` (which
invokes `affinescript compile`).
- package.json `main` -> ./src/index.cjs; `compile`
invokes `affinescript compile`; TS
devDeps removed; version bumped 0.2.0 ->
0.3.0 to mark the rewrite.
Removed:
- src/extension.ts (replaced)
- tsconfig.json (no TS to compile)
Acceptance-criteria coverage from affinescript#64:
- activate: wired via shim.activate (registers ExtensionContext handle).
- command registration: my-lang.{run,build,test} registered via
Vscode.registerCommand with wasm-table indices.
- LSP wiring: VscodeLanguageClient.newLanguageClient + .start() using
the my-lsp binary from the my-lang.lsp.path config.
- clean disposal: shim.deactivate is wired; LanguageClient handle is
not retained across activations (host process exit closes the pipe),
matching the affinescript pilot pattern.
Known small degradations vs. the original .ts (acceptable for this
first cut; can be tightened once the binding surface grows):
- my-lang.test no longer cd's into workspaceFolders[0] before running
`my-test`. The current Vscode.affine binding set has no
workspaceFolders accessor; VS Code's default terminal cwd is the
first workspace folder anyway, so the observable behaviour is the
same for single-root projects.
- LSP documentSelector is `{ scheme: "file" }` (any file) rather than
`{ scheme: "file", language: "my" }`. The vendored adapter mirrors
the upstream default; the LSP itself filters by file content.
- `synchronize.fileEvents` glob `**/*.my` is not wired — the LSP loses
the workspace-side file-watcher feedback loop but functions for
open-document interactions. Tracked for follow-up when the bindings
expose createFileSystemWatcher with LanguageClient synchronize.
Notes on the TS-exemption table mentioned in affinescript#64:
The exemption row for vscode-extension/src/extension.ts lives on
branch feat/stdlib-fs-env-format (not yet merged to main). On main
there is no TS-exemption table to update; when that branch lands, the
row for this file should be dropped at the same time.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced May 11, 2026
Merged
hyperpolymath
added a commit
to hyperpolymath/standards
that referenced
this pull request
May 11, 2026
…(affinescript#64) (#46) ## Summary Ports `rhodium-standard-repositories/satellites/rsr-certifier/extensions/vscode/src/extension.ts` (380 LOC) to AffineScript. Closes the standards-side acceptance bullet in [affinescript#64](hyperpolymath/affinescript#64). ### Dependencies (must land first) 1. [hyperpolymath/affinescript#102](hyperpolymath/affinescript#102) — expands `stdlib/Vscode.affine` + the `packages/affine-vscode/mod.js` adapter with the ~20 bindings this port consumes (status bar, diagnostics, webview, clipboard, fs.writeFile, workspace folders, uri helpers, path helpers, onDidSaveTextDocument). 2. The vendored adapter in `src/affine-vscode-adapter.cjs` is a verbatim copy of the updated `mod.js`. If #102 changes during review, this file needs a re-sync. ## What changed | File | Status | Purpose | |---|---|---| | `…/extensions/vscode/src/extension.affine` | **new** | AffineScript source-of-truth. Ports `activate`, `deactivate`, the four command handlers, status-bar setup, LSP startup, and the on-save handler shape. | | `…/extensions/vscode/src/affine-vscode-adapter.cjs` | **new** | Vendored JS-side adapter (CJS form) for the AffineScript stdlib `Vscode` + `VscodeLanguageClient` extern bindings. Copy of [`affinescript:packages/affine-vscode/mod.js`](https://github.com/hyperpolymath/affinescript/blob/main/packages/affine-vscode/mod.js). Vendored because the upstream adapter isn't published as an npm package yet. | | `…/extensions/vscode/src/index.cjs` | **new** | Runtime entry point. Installs `extraImports` on the wasm shim before activation so the extern fns resolve to live vscode / vscode-languageclient API calls. | | `…/extensions/vscode/out/extension.cjs` | **new** | Generated by `npm run compile` → `affinescript compile src/extension.affine -o out/extension.cjs`. Committed so the extension can be installed without an AffineScript toolchain on PATH. | | `…/extensions/vscode/package.json` | modified | `main` → `./src/index.cjs`; `compile` invokes `affinescript compile`; TS/eslint devDeps dropped; version `0.1.0` → `0.2.0`. | | `…/extensions/vscode/src/extension.ts` | **deleted** | Replaced. | | `…/extensions/vscode/tsconfig.json` | **deleted** | No TypeScript to compile. | ## Acceptance criteria (from [affinescript#64](hyperpolymath/affinescript#64)) - [x] [affinescript#35](hyperpolymath/affinescript#35) has landed. - [x] Port `rsr-certifier/extensions/vscode/src/extension.ts` → `.affine`. - [x] **Activation** verified via `shim.activate` (registers `ExtensionContext` handle, instantiates wasm with `extraImports`, sets up status bar, registers commands, starts LSP). - [x] **Command registration** verified — `rsr.checkCompliance`, `rsr.initConfig`, `rsr.showReport`, `rsr.generateBadge` registered via `Vscode::registerCommand` with wasm-table indices `0`–`3` (order matches handler declarations in `extension.affine`). On-save handler at index `4`. - [x] **LSP wiring** verified — `VscodeLanguageClient::newLanguageClient` + `languageClientStart`, using `rsr.serverPath` config or `context.asAbsolutePath("server/rsr-lsp[.exe]")` fallback (platform-aware via `processPlatform`). - [x] **Clean disposal** verified — `shim.deactivate` exported; status-bar item, diagnostic collection, and all command disposables join `ctx.subscriptions` for host-managed release. ## Feature-parity degradations The current AffineScript extern-call ABI is synchronous, so two Thenable-returning vscode APIs cannot be bound: | API | Used by | Effect on port | |---|---|---| | `vscode.window.withProgress(opts, async task)` | the "preferred" `checkCompliance` path | Removed. All four commands shell out to the `rsr` CLI in a terminal — the same fallback the original TS extension already used for the no-LSP case. | | `LanguageClient.sendRequest(method, params)` | `rsr/getCompliance` custom request | Removed. The downstream effects (status-bar mutation on every check result, diagnostic-collection updates) also go. The status bar shows a static initial value; the diagnostic collection is created and disposed but not populated. | `onDidSaveTextDocument`: the handler drops the `TextDocument` argument at the FFI boundary (wasm-table thunks are zero-arg in this adapter). The on-save handler is a no-op to avoid spawning a terminal on every save anywhere; the `rsr.checkOnSave` flag is honoured at the registration level so the wiring is in place once an async-extern ABI lands. `showReport` webview renders a constant placeholder shape rather than per-check data (the per-check data flowed from the `sendRequest` path that we cannot bind). The compile step produces 7 advisory `If without else returns Never` warnings — these are the same early-return-`if` pattern the affinescript pilot extension uses, and are cosmetic. ## TS-exemption table The repo's `.claude/CLAUDE.md` "TypeScript Exemptions" table currently lists only `avow-protocol/telegram-bot/avow-telegram-bot/**`. The rsr-certifier `extension.ts` was **not** a per-repo exemption row — it was covered by the universal-allowlist `*vscode*` directory-segment pattern in `.github/workflows/rsr-antipattern.yml`. Removing the .ts file therefore does not require a CLAUDE.md table edit; the file simply ceases to exist. ## Test plan - [ ] [affinescript#102](hyperpolymath/affinescript#102) is merged and a release is cut (or local toolchain points at that branch). - [ ] `npm run compile` succeeds with the AffineScript toolchain on PATH (or `AFFINESCRIPT_STDLIB` env var pointing at `affinescript/stdlib`). Confirmed locally: compiles to `out/extension.cjs` cleanly. - [ ] Install the extension into VS Code (`vsce package` + `code --install-extension rsr-certified-0.2.0.vsix`). - [ ] Open a folder with a `.git` directory or `.rsr.toml` — extension activates; console shows `"RSR-Certified extension is activating..."`; status bar shows `☆ RSR: SILVER 75%`. - [ ] `Cmd/Ctrl+Shift+P` → `RSR: Check Compliance` — opens terminal `RSR Check`, runs `rsr check "<workspace>"`. - [ ] `RSR: Initialize Configuration` — writes `.rsr.toml` at workspace root and opens it; info message `"RSR configuration created: .rsr.toml"`. - [ ] `RSR: Show Compliance Report` — opens webview panel with the placeholder report shape. - [ ] `RSR: Generate Badge` — copies badge markdown to clipboard; info message confirms. - [ ] Click the status bar item — fires `rsr.showReport`, panel opens. - [ ] If `rsr-lsp` is on PATH (or bundled at `server/rsr-lsp[.exe]`), LSP starts. If absent, the warning `"RSR LSP server not found. Some features may be limited."` shows; extension continues without LSP. - [ ] Reload window — `deactivate` runs cleanly; no disposable leaks; CI antipattern check passes (no `.ts` files). ## Related - Issue: [affinescript#64](hyperpolymath/affinescript#64) - Companion: [hyperpolymath/affinescript#102](hyperpolymath/affinescript#102) (binding-surface expansion — blocker) - Companion: [hyperpolymath/my-lang#11](hyperpolymath/my-lang#11) (my-lang side of the same issue — uses only the pre-existing binding surface) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
vscode-extension/src/extension.ts(the only TypeScript file in this repo's VS Code extension) to AffineScript per the language-policy migration target (RS/TS/JS → AffineScript → typed-wasm).stdlib/Vscode.affine+stdlib/VscodeLanguageClient.affine) has landed.What changed
vscode-extension/src/extension.affineactivate,deactivate, the three command handlers (my-lang.run,my-lang.build,my-lang.test), and LSP startup.vscode-extension/src/affine-vscode-adapter.cjsaffinescript:packages/affine-vscode/mod.jsin CJS form. Maps eachextern fnin the bindings to a realvscode/vscode-languageclient/nodecall. Vendored because the upstream adapter isn't yet published as an npm package.vscode-extension/src/index.cjsextraImportson it from the vendored adapter, then re-exportsactivate/deactivate. This is what VS Code's extension host loads (maininpackage.jsonpoints here).vscode-extension/out/extension.cjsnpm run compile→affinescript compile src/extension.affine -o out/extension.cjs. Committed so the extension can be installed without the AffineScript toolchain on PATH.vscode-extension/package.jsonmain→./src/index.cjs;compileinvokesaffinescript compile; TS devDeps (@types/*,typescript) dropped; version0.2.0→0.3.0to flag the rewrite.vscode-extension/src/extension.tsvscode-extension/tsconfig.jsonAcceptance criteria (from affinescript#64)
vscode-extension/src/extension.ts→.affine.shim.activate(registers theExtensionContextas an opaque handle, wires bindings before instantiating wasm).my-lang.run,my-lang.build,my-lang.testregistered viaVscode::registerCommandwith wasm-table indices0,1,2(order matches handler declarations inextension.affine).VscodeLanguageClient::newLanguageClient+languageClientStart, using themy-lspbinary resolved from themy-lang.lsp.pathconfiguration.shim.deactivateexported; command disposables are pushed toctx.subscriptionsso the host releases them at extension unload. (Matches the affinescript pilot's intentional best-effort LSP stop.)Known small degradations vs. the original .ts
These are acceptable for the first cut; they can be tightened once the affinescript binding surface grows (tracked in affinescript#64 follow-ups):
my-lang.testno longercds intoworkspaceFolders[0]. The currentVscode.affinebinding set has noworkspaceFoldersaccessor. VS Code's default terminal cwd is the first workspace folder anyway, so single-root projects see the same behaviour; multi-root projects lose the explicit targeting.documentSelectoris{ scheme: "file" }(any file) rather than{ scheme: "file", language: "my" }. The vendored adapter mirrors the upstream default; the LSP itself filters by file content / extension.synchronize.fileEventsfor the**/*.myglob is not wired — the LSP loses the workspace-side file-watcher feedback loop but still functions for open-document interactions.Note on the TS-exemption table
affinescript#64 lists this acceptance bullet:
The exemption row for
vscode-extension/src/extension.tslives on branchfeat/stdlib-fs-env-format, not yet merged tomain. Onmainthere is no TS-exemption table to update; when that feature branch lands, the row for this file should be dropped at the same time.Test plan
npm run compilesucceeds with the AffineScript toolchain on PATH (orAFFINESCRIPT_STDLIBenv var pointing ataffinescript/stdlib).vsce package+code --install-extension my-lang-0.3.0.vsix)..myfile — extension activates (onLanguage:my); console shows"My Language extension activated".Cmd/Ctrl+Shift+P→My: Run File— opens a terminal namedMy Language, runsmy run "<path>".My: Build Binary— runsmy build "<path>" -o "<path without .my>".My: Run Tests— opens terminalMy Language Tests, runsmy-test.my-lspis on PATH, LSP starts (hover / completion / diagnostics work). If not, the extension still activates; LSP wiring fails silently as in the original.deactivateruns cleanly, no disposable leaks.🤖 Generated with Claude Code