Repository navigation
feat(glsp-client): ship the GLSP client classes for every host - #419
Merged
Merged
Conversation
martin-fleck-at
force-pushed
the
feat/glsp-client-package
branch
from
October 13, 2026 15:09
fa2c2e3 to
12b5e33
Compare
martin-fleck-at
force-pushed
the
feat/glsp-client-package
branch
4 times, most recently
from
October 13, 2026 15:48
ea3f611 to
2428371
Compare
The framework's GLSP client classes lived in glsp-client-theia, so a browser page or a VS Code webview got none of them: a failed load vanished as an uncaught rejection, sprotty's view-registration errors went to its NullLogger, and only the Theia module repaired routes. New package @hydranium/glsp-client, with no Theia dependency - Move the action dispatcher, diagram loader, hidden-bounds updater, status overlay, GLSP client and bind recorder out of glsp-client-theia - Inject the logger, tracer and clock through HydraniumClientTypes, typed by the protocol interfaces, so each host binds its own - Declare the load failure as DIAGRAM_LOAD_FAILED in a module of its own, so ./messages loads no GLSP, and format its English in the neutral loader - Add SprottyLoggerAdapter, so sprotty's errors reach the host's logger with the calling class nested under its tag; its chatter goes to trace and debug with parameters reduced to names, its silently resolved request timeout to warn - Add createGlspClientModule, which rebinds the classes and sprotty's logger; a passed logger replaces a host binding, and a host that neither binds nor passes one gets the console - Gate the three entries in check:neutral and the Node-global lint scope, compile the README snippet, run the Theia range probe on a change here, and name the browser-bound root and the token registry in the conventions - Resolve the real classes through both binders in a GLSP container, so a wrong injection token fails the suite rather than a host glsp-client-theia binds through it - createGlspClientTheiaModule binds the tokens from the Output channel, keeping the per-class tag, before calling the neutral binder - HydraniumGlspTheiaDiagramLoader renders the failure through nls under the existing key; a test holds its English equal to the declaration - Drop the ./testing subpath, whose only content moved - Alias the sibling to its sources under vitest, since its CommonJS lib requires GLSP's stylesheets through Node past the prebundle Hosts - The browser page and the VS Code webview call the binder; the Theia configuration drops its hand-rolled sprotty logger rebind - The page tags the client's lines GLSP client, apart from the head's - The browser console test expects the dispatcher's two model-initialized lines, which the page logger now carries Breaks for Theia adopters: the moved classes import from the new package, the classes' channel field is hydraniumLogger, and @hydranium/glsp-client-theia/testing is gone. Fixes #150
martin-fleck-at
force-pushed
the
feat/glsp-client-package
branch
from
October 13, 2026 16:02
2428371 to
6f1b201
Compare
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.
The framework's GLSP client classes lived in
glsp-client-theia, so a browser page or a VS Code webview got none of them: a failed load vanished as an uncaught rejection, sprotty's view-registration errors went to its defaultNullLogger, and only the Theia module repaired the routescalcRoutecollapses while obstacles are unmeasured. This adds@hydranium/glsp-client, with no Theia dependency, moves the classes that are not Theia's by nature into it, and gives every host one binder.glsp-client-theiadepends on it and binds through it; order-flow's browser page and VS Code webview call the same binder the Theia module calls.What moves.
HydraniumGlspActionDispatcher,HydraniumDiagramLoaderandHydraniumHiddenBoundsUpdaterinject their logger, tracer and clock throughHydraniumClientTypes, typed by the protocol interfaces, instead of the Theia channel classes.HydraniumStatusOverlay,HydraniumGlspClientand the bind recorder move as they are. The loader's failure message is declared asDIAGRAM_LOAD_FAILEDunder./messages; the neutral loader formats its English and the Theia subclassHydraniumGlspTheiaDiagramLoaderrenders it throughnlsunder the existing key.The binder.
createGlspClientModule(context, { logger? })rebinds the four classes and sprotty'sTYPES.ILoggertoSprottyLoggerAdapter, which forwards to the host's logger. It binds a protocolConsoleLoggeronly when the host passed none and bound none, and aDefaultTracerover the bound logger and clock when the tracer is unbound.createGlspClientTheiaModulebinds the three tokens from the Output channel first, with the per-class tag and a lazy bridge to client-theia'sClock, then calls the neutral binder and rebinds the loader to the Theia one.Breaks for Theia adopters. The moved classes import from
@hydranium/glsp-client, whichglsp-client-theialists as a peer. The three classes'channelfield is nowhydraniumLogger, typedLogger.@hydranium/glsp-client-theia/testingis gone; the bind recorder is@hydranium/glsp-client/testing. sprotty'sTYPES.LogLevelno longer filters anything: the adapter reports sprotty's most verbose level and the framework threshold decides.Decisions and their cost
HydraniumClientTypes. As the server'sHydraniumTypes, so a token's name cannot collide with the type it injects. The identifier helper stays private until an adopter mints a client token.Clockcarries no DI coupling by design; the Theia binder bridges the two tokens with one lazy binding, so a clock an adopter module binds later is still used.hydraniumLogger, notlogger.GLSPActionDispatcherandGLSPHiddenBoundsUpdateralready carry sprotty'slogger: ILogger, which is why the field waschannel; the new name says which logger it is on every host.ConsoleLogger, which is loud; the classes themselves require the token, so a container that unbinds it fails at resolution rather than running silent.loggoes totrace, andinfotodebug, with parameters reduced to their names. sprotty passes whole actions and models there, and the Theia channel logger stringifies every parameter as JSON, so forwarding them would write the model into the Output channel on every action; an action'skindor an object's class is what the line keeps, soHandle requestModelandExecuting SetModelCommandstill say what happened. sprotty'sinfois diagnosis, chatty on every hover's feedback, so the level isdebug; the one anomaly reported there, a request GLSP resolved silently after its timeout, is raised towarnby matching GLSP's wording, degrading todebugif upstream rewords it.errorandwarnkeep their parameters whole, where the parameter is the useful part.sub, notfor, sinceforreplaces the host's component: the page's lines read[GLSP client :: Viewer]and Theia's[SprottyLoggerAdapter :: Viewer], so the origin is a tag the host renders as every other component, not a prefix inside the message. Where sprotty passes a sentence as the caller, as its layout registries do, the sentence prefixes the message instead of being dropped. A derivation per line was rejected for its allocation on every action; one per class costs a few dozen loggers, andlogandinfocheck the framework threshold before formatting a line at all. The adapter's test runs over a realAbstractLogger, since a double recording the name it was handed cannot tell a nested tag from a replaced one. The message GLSP sends an action in names the action too, so the outgoing half of the traffic reads as the incoming one.@injectwould pass them and fail only on a host, so one test per package builds a container over GLSP's default modules and resolves the five tokens to the real classes, with the passed logger and the clock fallback checked on the dispatcher.GLSP client, beside theGLSP headtag its connection carries, so a load failure the page itself reports does not read as a line the worker sent.bindChannelLoggerbinds the channel logger; an adopter who binds one of the tokens does so after the module, as for every token it binds.libis CommonJS, so itsrequireof@eclipse-glsp/clientreaches the stylesheets through Node past the prebundle; the e2e tiers exercise the built artefact.hydranium/glsp-client/diagram-load-failed; the Theia key stayshydranium/glsp-client-theia/diagram-load-failed, so each side's catalogue holds the code of the side that renders it. A test holds the two English texts equal.@eclipse-glsp/client's: it renders and loads stylesheets, so it needs a bundler with a CSS loader. The host-integration root rule in the conventions names it beside the Theia packages; moving the classes to a./browsertier would leave an empty root../messagesloads no GLSP.DIAGRAM_LOAD_FAILEDis declared in a module of its own rather than in the loader that raises it, so a bundle that only translates the code, such as a properties webview, needs no CSS loader.check:neutralgates the barrel for Node imports and does not look inside GLSP, so the claim rests on the module's imports.options.loggerrebinds when the token is already bound, since two bindings on one token make every resolution ambiguous.DiagramLoadertwice. The neutral binder binds the neutral loader, the Theia binder replaces it; the same one-line move a browser adopter with a catalogue of their own makes.info; the test asserts exactly those two lines rather than filtering them, so a framework line that stops arriving is seen too. The duration and timer id are matched loosely, since the tracer prints seconds past one second and numbers timers module-wide.How I know it works
logtodebugfails the adapter test, as does routing the timeout notice todebug, dropping the guard on a prototype-less parameter deriving the caller's logger withforinstead ofsub, and formatting a line below the threshold; dropping theTYPES.ILoggerrebind fails the binder test; always binding a passed logger fails the replacement test../messagesbarrel in bare Node loads no GLSP module.check:neutral,check:glob-coverage,check:exports,check:readme,check:readmes,check:deps,check:phantom-deps,check:nls-extract,check:protected-signatures,check:ast-grep,check:docsand the formatter pass locally, run after the new files were staged.Follow-ups