Monaco Kusto
Kusto Query Language (KQL) support for the Monaco Editor — completions, validation, hovers, folding, and syntax highlighting out of the box.
Repository Health
Technical Analysis
@kusto/monaco-kusto is Microsoft’s official Monaco Editor language plugin for Kusto Query Language (KQL), the query language behind Azure Data Explorer, Azure Monitor, and Microsoft Sentinel. It registers a kusto language mode with Monaco and wires up a dedicated web worker running a real Kusto parser and semantic analyzer — the same language service used by Azure’s own web tooling — so editors get accurate completions, syntax and semantic validation, hovers, folding, formatting, go-to-definition, find-references, and rename support instead of a generic regex-based grammar.
Because the underlying language service is a large C#-originated component bridged to JavaScript (distributed as @kusto/language-service and @kusto/language-service-next), all analysis work happens off the main thread inside the worker. Consumers push a live cluster schema via setSchema/setSchemaFromShowSchema so completions and diagnostics stay in sync with real table and column definitions, making the plugin the standard choice for any web-based KQL editing surface — from Kusto Explorer and Azure Data Explorer’s own web UX to third-party observability and security tooling built on Monaco.
What You Get
- Full KQL language mode - registers a
kustolanguage with Monaco covering.csland.kqlfiles - Schema-aware IntelliSense -
setSchema/setSchemaFromShowSchemafeed live cluster/database/table schemas into the completion and validation engine - Dedicated web worker - all parsing, semantic analysis, and Kusto language-service calls run off the main thread via
getKustoWorker() - Rich editing features - hovers, folding, document/range formatting, go-to-definition, find-references, and rename, all wired through standard Monaco language provider APIs
- Prebuilt syntax themes - ships
kusto-light/kusto-darkMonaco themes plus Monarch tokenization and semantic highlighting
Common Use Cases
- Embedding a KQL query editor - add Azure Data Explorer/Kusto query editing to an internal dashboard or admin tool built on Monaco
- Building observability and security UIs - power query editors for Azure Monitor Logs, Microsoft Sentinel, or Application Insights-style log-analytics dashboards
- Schema-driven autocomplete - surface table/column-aware completions once a cluster’s schema is fetched via
.show schema as json - Client-side query validation - catch KQL syntax and semantic errors before submitting a query to a cluster
Under The Hood
Architecture
The plugin layers cleanly from the outside in: monaco.contribution.ts registers the kusto language and exposes the public global API (monaco.languages.kusto), kustoMode.ts wires up all Monaco language-feature providers (completion, diagnostics, hover, folding, formatting, definition, rename, reference) against a shared AugmentedWorkerAccessor, workerManager.ts owns the lifecycle of the underlying web worker (idle-timeout handling, schema persistence across worker restarts, lazy worker creation), and kustoWorker.ts is the RPC surface actually running inside that worker, delegating to kustoLanguageService.ts which wraps the bridged Kusto language engine. Cross-thread schema propagation (setSchema/setSchemaFromShowSchema) and an onSchemaUpdateComplete emitter tie the layers together so semantic tokens stay consistent after a schema push. A handful of pragmatic workarounds — an Object.create/Object.assign proxy-safe override pattern for augmenting worker methods, an explicit throwaway ‘ignore’ postMessage before sending real worker init data, and a setTimeout-based suggest-dialog retrigger — reveal a codebase that has hardened around real Monaco/worker quirks over many releases rather than a theoretically pure design.
Tech Stack
TypeScript targeting es5/esnext module output, bundled with Rollup into ESM-only release artifacts (AMD dropped as of v15), against a monaco-editor peer dependency pinned to ^0.55.0. The actual Kusto parsing/semantic-analysis engine ships as two dependencies, @kusto/language-service and @kusto/language-service-next, C#-originated code migrated to TypeScript via a Bridge.NET-style toolchain and consumed here as opaque global namespaces (Kusto.Language.*). Supporting libraries include xregexp for extended regex handling, vscode-languageserver-types/vscode-languageserver-textdocument for LSP-shaped data structures, and lodash-es. The repo is a Yarn 3 (Berry) workspace with package (the library) and samples/* (Parcel, Vite, Webpack+React integration examples) as separate workspace packages, built via ts-node scripts rather than a generic task runner.
Code Quality
Unit tests run under Jest across src/**/*.spec.ts (completion filtering, semantic tokens registration, worker mode setup, range-HTML rendering), and a separate Playwright integration suite under tests/integration exercises the editor, completions, doc comments, and syntax highlighting end-to-end in a real browser. CI runs via .github/workflows/main.yml and pr.yml, and Prettier enforces formatting. Error handling favors defensive console.error + early null/Promise.resolve(null) returns over thrown exceptions when a document/model can’t be resolved, which is pragmatic for a worker RPC boundary but means callers must handle nulls throughout. No systemic use of stricter TypeScript strict-mode flags is evident in tsconfig.json beyond isolatedModules, so type safety leans on the bridged language-service’s own generated types rather than the plugin’s own code being maximally strict.
API Design
The consumer-facing surface is small and focused: register the kusto language, call monaco.languages.kusto.getKustoWorker() to get a worker handle, and push a schema with setSchema. Most Monaco language-provider wiring (hover, completion, folding, etc.) happens automatically once a model’s language is set to kusto, so day-to-day usage requires little boilerplate. The rough edge is web-worker bundler wiring: consumers must configure MonacoEnvironment.getWorker/getWorkerUrl to route the 'kusto' label to a dedicated worker entry point that imports both the kusto worker and Monaco’s own editor worker — a requirement the README documents at length precisely because upstream monaco-editor changes (0.53+) silently broke the old routing approach. Naming is consistent with Monaco’s own APIs (registerHoverProvider-style adapters), lowering the learning curve for anyone who has used Monaco’s language API surface before.