Problem
The Node-CJS codegen (lib/codegen_node.ml, added by #35 / #90) emits a .cjs shim that wraps the compiled wasm module. The shim exposes an extraImports hook that callers populate with the concrete vscode-API bindings before activate fires:
// Inside the generated extension.cjs:
const extras = (typeof exports.extraImports === "function")
? exports.extraImports()
: {};
return { wasi_snapshot_preview1, ...extras };
Today, every consumer hand-writes a wrapper file to install extraImports before vscode's extension host calls activate. The pattern is identical across the three current consumers:
// hyperpolymath/my-lang:vscode-extension/src/index.cjs
// hyperpolymath/standards:rsr-certifier/extensions/vscode/src/index.cjs
// hyperpolymath/affinescript:editors/vscode/src/index.cjs (still to land)
const shim = require("../out/extension.cjs");
const makeVscodeBindings = require("./affine-vscode-adapter.cjs");
// or: const makeVscodeBindings = require("@hyperpolymath/affine-vscode");
shim.extraImports = () => makeVscodeBindings(
require("vscode"),
require("vscode-languageclient/node"),
shim,
);
exports.activate = shim.activate;
exports.deactivate = shim.deactivate;
This boilerplate is 100% mechanical and identical in every extension. It's what's left to manually wire — and it's the thing #35's original plan called out as belonging in codegen:
(Real wiring belongs in the codegen — Phase 3 will replace this manual hookup with auto-generated glue once extension.affine is the source of truth for the extension entry point.)
— packages/affine-vscode/README.adoc
Proposed plan
Add a codegen flag, e.g. --vscode-extension, that opts into emitting the wiring inline so the generated .cjs is directly loadable as a VS Code extension's main:
affinescript compile src/extension.affine -o out/extension.cjs --vscode-extension
The emitted shim then includes the equivalent of:
// Inserted by --vscode-extension:
const makeVscodeBindings = require("@hyperpolymath/affine-vscode");
exports.extraImports = function() {
return makeVscodeBindings(
require("vscode"),
require("vscode-languageclient/node"),
exports,
);
};
… with @hyperpolymath/affine-vscode listed in the extension's package.json dependencies. (Once the npm-publish follow-up lands — see the sibling follow-up issue — this is a normal npm install.)
Each consumer's package.json main then points directly at out/extension.cjs. No hand-written index.cjs, no vendored affine-vscode-adapter.cjs file.
Sub-flags
--vscode-extension-adapter <module-specifier> — override the require() specifier for the adapter (useful for testing against a local checkout or for extensions that vendor their own).
--vscode-extension-no-lc — for extensions that don't ship a language client (no vscode-languageclient/node dependency); the wiring skips that require and passes null.
Acceptance criteria
Out of scope
- A general
--vscode-target-language-server-extension shape for extensions that aren't language-server-shaped. This issue covers the LSP+commands pattern that the current adapter implements.
- A browser-host webworker variant (Node-only for now).
Related
Problem
The Node-CJS codegen (
lib/codegen_node.ml, added by #35 / #90) emits a.cjsshim that wraps the compiled wasm module. The shim exposes anextraImportshook that callers populate with the concrete vscode-API bindings beforeactivatefires:Today, every consumer hand-writes a wrapper file to install
extraImportsbefore vscode's extension host callsactivate. The pattern is identical across the three current consumers:This boilerplate is 100% mechanical and identical in every extension. It's what's left to manually wire — and it's the thing #35's original plan called out as belonging in codegen:
—
packages/affine-vscode/README.adocProposed plan
Add a codegen flag, e.g.
--vscode-extension, that opts into emitting the wiring inline so the generated.cjsis directly loadable as a VS Code extension'smain:The emitted shim then includes the equivalent of:
… with
@hyperpolymath/affine-vscodelisted in the extension'spackage.jsondependencies. (Once the npm-publish follow-up lands — see the sibling follow-up issue — this is a normalnpm install.)Each consumer's
package.jsonmainthen points directly atout/extension.cjs. No hand-writtenindex.cjs, no vendoredaffine-vscode-adapter.cjsfile.Sub-flags
--vscode-extension-adapter <module-specifier>— override therequire()specifier for the adapter (useful for testing against a local checkout or for extensions that vendor their own).--vscode-extension-no-lc— for extensions that don't ship a language client (novscode-languageclient/nodedependency); the wiring skips thatrequireand passesnull.Acceptance criteria
affinescript compile src/extension.affine -o out/extension.cjs --vscode-extensionemits a fully-wired CJS module.package.jsonmainpoints at the unmodified generated.cjsactivates and disposes cleanly.editors/vscode/is migrated off the hand-writtenindex.cjs(once that wrapper exists; this work and the affinescript-pilot port in [Repo] Port editors/vscode/src/extension.ts to .affine once #35 lands #63 likely coordinate).index.cjs+ vendored adapter both disappear).--vscode-extensionflag.Out of scope
--vscode-target-language-server-extensionshape for extensions that aren't language-server-shaped. This issue covers the LSP+commands pattern that the current adapter implements.Related
_buildImports()in the emitted.cjsrequire("@hyperpolymath/affine-vscode")to resolve in consumer projects.