feat(vscode-bindings): expand surface for rsr-certifier port (#64)#102
Merged
Conversation
Adds ~20 new extern fns + 5 opaque handle types to stdlib/Vscode.affine and their JS-side implementations to packages/affine-vscode/mod.js, so the rsr-certifier extension in hyperpolymath/standards can be ported to .affine with full feature parity (issue #64 acceptance bullet 2). Bindings added — see stdlib/Vscode.affine for shapes: Workspace: workspaceFolderFirstPath, workspaceRootUri Uri / file-system / text documents: uriFromPath, uriJoinPath, uriPath, fsWriteFile, openTextDocument, showTextDocument Status bar: createStatusBarItem + setText / setTooltip / setCommand / setBackgroundColorTheme / show / hide / asDisposable Diagnostics (JSON-shaped to avoid Range/Diagnostic struct FFI): createDiagnosticCollection + clear / setForUri / asDisposable Webview: createWebviewPanel + setHtml / asDisposable Clipboard: clipboardWriteText Events: onDidSaveTextDocument (handler is a zero-arg wasm-table thunk; the TextDocument arg from the underlying vscode event is dropped at the FFI boundary — handlers that need the saved file path can call editorActiveFilePath() inside the thunk) Path helpers / process / context: pathBasename, pathJoin, processPlatform, extensionAbsolutePath New opaque types: StatusBarItem, DiagnosticCollection, WebviewPanel, Uri, TextDocument. Two API shapes deliberately omitted because they require an async-extern ABI that doesn't exist yet: vscode.window.withProgress(opts, async task) -- task is Thenable-returning. LanguageClient.sendRequest(method, params) -- returns a Thenable. Extensions that need either should fall back to terminal / execSync shells until async externs land. Both omissions are noted in stdlib/Vscode.affine and in packages/affine-vscode/README.adoc. Verification: $ AFFINESCRIPT_STDLIB=$PWD/stdlib affinescript compile \ /tmp/test-new-bindings.affine -o /tmp/test-bindings.cjs Compiled ... -> /tmp/test-bindings.cjs (Node-CJS) A smoke-test .affine exercising every new binding compiles cleanly via the existing affinescript compiler — no codegen changes needed; the new symbols flow through the existing extern-resolution + Wasm-import- emission paths. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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 was referenced May 11, 2026
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
Expands
stdlib/Vscode.affine(and the JS adapter atpackages/affine-vscode/mod.js) with ~20 new extern bindings + 5 opaque handle types, so the rsr-certifier extension inhyperpolymath/standardscan be ported to.affinewith full feature parity. This unblocks the standards-side acceptance bullet in #64.This is the on-demand expansion contemplated by #35 ("Add symbols on demand — keep this file's growth proportional to real consumers."). The new surface is exactly what rsr-certifier's existing
extension.tsuses; it does not aim to mirror the full vscode API.What was added
New opaque types
StatusBarItem,DiagnosticCollection,WebviewPanel,Uri,TextDocument.New
extern fnsworkspaceFolderFirstPath,workspaceRootUriuriFromPath,uriJoinPath,uriPath,fsWriteFile,openTextDocument,showTextDocumentcreateStatusBarItem,statusBarItem.{setText,setTooltip,setCommand,setBackgroundColorTheme,show,hide,asDisposable}createDiagnosticCollection,diagnosticCollection.{clear,setForUri,asDisposable}createWebviewPanel,webviewPanel.{setHtml,asDisposable}clipboardWriteTextonDidSaveTextDocumentpathBasename,pathJoin,processPlatform,extensionAbsolutePathEach binding has a corresponding implementation in
packages/affine-vscode/mod.js(~170 added lines).Design choices worth flagging
Range/Diagnosticstructs.diagnosticCollectionSetForUritakes a JSON array of{startLine,startCol,endLine,endCol,message,severity}objects — the adapter parses + constructs the vscode objects. This keeps the binding surface flat without an array-of-records ABI.onDidSaveTextDocumentdrops theTextDocumentarg at the FFI boundary. Wasm-table handler thunks are zero-arg in this adapter; handlers that need the saved file path can calleditorActiveFilePath()inside the thunk (95% case: the saved doc is the active editor). Documented inline instdlib/Vscode.affine.asDisposableaccessors are identity casts forStatusBarItem/DiagnosticCollection/WebviewPanel— the underlying JS objects implement theDisposableinterface, so handing the handle back unchanged is correct.Deliberate omissions
Two API shapes are not bound because they cannot be expressed in the current synchronous extern-call ABI:
vscode.window.withProgress(opts, async task)— second arg is a Thenable-returning task.LanguageClient.sendRequest(method, params)— returns a Thenable.Extensions that need either should fall back to terminal /
execSyncshells (the same fallback path the existing rsr-certifier extension already has for the no-LSP case). Both omissions are documented instdlib/Vscode.affineandpackages/affine-vscode/README.adoc.Verification
A smoke-test
.affineexercising every new binding compiles cleanly via the existing toolchain (no codegen changes needed — new symbols flow through the existing extern-resolution + Wasm-import-emission paths):The existing pilot at
editors/vscode/src/extension.affinestill compiles unchanged (uses only the pre-existing bindings; this PR is purely additive).Test plan
editors/vscode/src/extension.affine) still compiles..affineusing every new binding compiles.hyperpolymath/standards(port rsr-certifier) compiles against this surface.vscode+vscode-languageclient/noderesolves all new imports through the adapter.Related
rhodium-standard-repositories/satellites/rsr-certifier/extensions/vscode/src/extension.ts.standards").🤖 Generated with Claude Code