WSO2 MI Language Server
An LSP server that brings validation, completion, hover, and navigation to WSO2 Micro Integrator (Synapse) XML configuration files — backed by a real Xerces schema validator compiled to WebAssembly.
Architecture
The layered design, the schema subsystem, and the two-engine model explained.
Flows & Sequences
Step-by-step diagrams: startup, validation, completion, config reload.
Component Reference
Every source file, what it owns, and who calls it.
What it does
The server speaks the Language Server Protocol over stdio with a VS Code
client. For each open .xml document it figures out which XSD applies, then
provides:
- Diagnostics — real XSD validation through Xerces (WASM), with syntax and schema errors in one pass.
- Completion & Hover — element and attribute suggestions from a hand-written XSD model.
- Structure — document symbols, folding ranges.
- Navigation — go-to-definition, find-references, rename, formatting (full and range).
Tech stack
| Concern | Choice | Where |
|---|---|---|
| LSP transport | vscode-languageserver/node | src/server.ts |
| XML parsing | @xml-tools/parser → custom AST | src/parser/ |
| Schema validation | Apache Xerces-C compiled to WASM | xerces-wasm/ |
| Completion model | Hand-written XSD reader | src/schema/xsdCompletionProvider.ts |
| Bundling | esbuild → single CJS file | dist/server.js |
| Tests | Vitest (328 tests) | tests/ |
The big picture
At the highest level, requests flow from the editor through a thin transport layer into a service façade, which fans out to feature providers and a schema subsystem. Diagnostics take a separate path straight to the WASM validator.
lifecycle + config"] RH["requestHandlers.ts
request → service"] end subgraph F["Service façade"] LS["xmlLanguageService.ts"] end subgraph Feat["Feature providers (services/)"] direction LR FX["hover · completion · folding
symbols · rename · definition
references · formatter"] end Parse["parser/
@xml-tools → xmlNode AST"] subgraph Sch["Schema subsystem (schema/)"] SA["SchemaAssociator
file → XSD"] SP["SchemaProvider
registry + caches"] CP["XsdCompletionProvider"] end DH["DiagnosticsHandler"] WASM["⚙️ Xerces WASM"] Client <-->|stdio JSON-RPC| Server Server --> RH Server --> DH RH --> LS LS --> Feat LS --> Parse LS --> SP SP --> SA SP --> CP DH --> SP DH -->|validate| WASM style Client fill:#1c2128,stroke:#ff7300,color:#f0f6fc style WASM fill:#1c2128,stroke:#3fb950,color:#f0f6fc style DH fill:#1c2128,stroke:#58a6ff,color:#f0f6fc
Heads up: diagnostics and completions are served by
two different schema engines (Xerces WASM vs. the hand-written
XsdCompletionProvider). That deliberate split is the most important thing to
understand about this codebase — it's explained in detail on the
Architecture page.
Repository at a glance
src/
├─ server.ts LSP entry: lifecycle, schema registration
├─ requestHandlers.ts maps LSP requests → service calls (+ parse cache)
├─ xmlLanguageService.ts façade returning one service object
├─ diagnosticsHandler.ts validation orchestration + schema-graph loading
├─ configuration.ts workspace {pattern, xsdPath} → associations
├─ parser/ @xml-tools CST → xmlNode AST
├─ services/ one file per LSP feature
└─ schema/
├─ schemaAssociator.ts file/namespace → XSD path
├─ schemaProvider.ts validator + completion-provider registry
├─ xsdCompletionProvider.ts hand-written XSD reader (completion/hover)
└─ xsdValidator.ts thin wrapper over the WASM validate()
xerces-wasm/ Apache Xerces-C compiled to WebAssembly
resources/schemas/ bundled Synapse XSDs (versions 430, 440)