✨ feat(playground): add type checking and inlay hints support#1398
✨ feat(playground): add type checking and inlay hints support#1398
Conversation
There was a problem hiding this comment.
Pull request overview
Adds type-checking-related UX in the web playground by extending the mq-web wrapper API and wiring Monaco diagnostics + inlay hints to new WASM-facing functions.
Changes:
- Expose
inlayHints(andInlayHinttype) frommq-web, and extenddiagnosticswith anenableTypeCheckflag. - Add a “Type Check” toggle in the playground, pass the toggle into diagnostics, and register a Monaco inlay-hints provider.
- Point the playground’s
mq-webdependency at the local package to consume these new APIs.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/mq-web/src/index.ts | Re-export inlayHints and InlayHint type from the WASM bindings. |
| packages/mq-web/src/core.ts | Add wrapper methods/signatures for inlayHints and diagnostics(..., enableTypeCheck?). |
| packages/mq-playground/src/Playground.tsx | Add UI toggle, pass flag into diagnostics, and register inlay hints provider. |
| packages/mq-playground/package.json | Use local mq-web package to pick up new APIs. |
| packages/mq-playground/package-lock.json | Lockfile updates for local linked mq-web. |
Files not reviewed (1)
- packages/mq-playground/package-lock.json: Language not supported
| export type { | ||
| Options, | ||
| Diagnostic, | ||
| InlayHint, |
There was a problem hiding this comment.
InlayHint is exported from ../mq-wasm/mq_wasm.js, but the current WASM bindings (crates/mq-wasm) don't define an InlayHint type in the generated TypeScript section. This will fail type-check/build for mq-web unless the WASM bindings are updated and regenerated. Either add InlayHint to crates/mq-wasm's TS custom section (and regenerate packages/mq-web/mq-wasm/*) or remove this export until the WASM layer provides it.
| InlayHint, |
| InlayHint, | ||
| ConversionOptions, | ||
| } from "./mq_wasm"; | ||
|
|
There was a problem hiding this comment.
core.ts now imports InlayHint from ./mq_wasm, but the current WASM bindings in this repo (crates/mq-wasm) only define DefinedValue, Diagnostic, and Options in their TypeScript custom section. Unless the WASM bindings are updated/regenerated to export InlayHint, this import will break the mq-web build.
| InlayHint, | |
| ConversionOptions, | |
| } from "./mq_wasm"; | |
| } from "./mq_wasm"; | |
| type InlayHint = unknown; | |
| type ConversionOptions = unknown; |
| toAst: wasmImport.toAst, | ||
| format: wasmImport.format, | ||
| diagnostics: wasmImport.diagnostics, | ||
| inlayHints: wasmImport.inlayHints, |
There was a problem hiding this comment.
initWasm() wires inlayHints: wasmImport.inlayHints, but the current WASM exports (crates/mq-wasm/src/script.rs) do not define or export an inlayHints function. As-is, wasm.inlayHints(...) will be undefined at runtime and the first call will throw. Implement and export inlayHints in the WASM crate (and regenerate bindings into packages/mq-web/mq-wasm) or add a defensive fallback in mq-web that returns an empty list when the export is missing.
| inlayHints: wasmImport.inlayHints, | |
| inlayHints: | |
| wasmImport.inlayHints ?? | |
| (async (_code: string): Promise<readonly InlayHint[]> => []), |
| ): Promise<ReadonlyArray<Diagnostic>> { | ||
| const wasm = await initWasm(); | ||
| return await wasm.diagnostics(code); | ||
| return await wasm.diagnostics(code, enableTypeCheck); |
There was a problem hiding this comment.
diagnostics(code, enableTypeCheck?) suggests the WASM layer can optionally run type checking, but the current WASM diagnostics export only accepts code: string and only returns parse errors. Passing this flag is ignored today, which makes the new Playground toggle misleading. Either extend the WASM diagnostics export to accept the flag and run type checking, or expose a separate typeDiagnostics(...)/check(...) API so callers can reliably request type errors.
| return await wasm.diagnostics(code, enableTypeCheck); | |
| return await wasm.diagnostics(code); |
| monaco.languages.registerInlayHintsProvider("mq", { | ||
| provideInlayHints: async (model: editor.ITextModel) => { | ||
| if (!enableTypeCheckRef.current) { | ||
| return { hints: [], dispose: () => {} }; | ||
| } | ||
| const hints = await mq.inlayHints(model.getValue()); | ||
| return { | ||
| hints: hints.map((hint: mq.InlayHint) => ({ | ||
| position: { | ||
| lineNumber: hint.line, | ||
| column: hint.column, | ||
| }, | ||
| label: hint.label, | ||
| kind: monaco.languages.InlayHintKind.Type, | ||
| })), | ||
| dispose: () => {}, | ||
| }; |
There was a problem hiding this comment.
The new inlay hints provider calls mq.inlayHints(...), but mq-web's wrapper currently points at a WASM export that doesn't exist in this repo (crates/mq-wasm doesn't export inlayHints). This will throw/reject during Monaco's inlay-hints requests. Either implement/regenerate the WASM export, or guard the provider with a feature-detection check (e.g., return no hints when mq.inlayHints is undefined) to avoid runtime failures.
00abd47 to
8e71666
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 2 changed files in this pull request and generated 3 comments.
Files not reviewed (1)
- packages/mq-playground/package-lock.json: Language not supported
Comments suppressed due to low confidence (1)
packages/mq-playground/package-lock.json:36
- This lockfile update removes
resolvedandintegrityfields for many registry packages (e.g.@babel/code-frame). That can reduce supply-chain protections (no integrity pinning) and may make installs less reproducible across environments/tools. If this wasn’t intentional, regeneratepackage-lock.jsonwith standard npm settings; if it is intentional, consider adding a repo-level note/config documenting the npm setting that strips these fields so future installs don’t reintroduce them.
| const errors = await mq.diagnostics( | ||
| model.getValue(), | ||
| enableTypeCheckRef.current, | ||
| ); | ||
| monaco.editor.setModelMarkers( |
There was a problem hiding this comment.
The diagnostics update is async but not tied to a specific model version. With type checking enabled (potentially slower), results can arrive out of order and apply markers for stale code. Consider capturing model.getVersionId() (or similar) before awaiting and skipping setModelMarkers if the model version has changed, or canceling/serializing in-flight diagnostics calls.
| const errors = await mq.diagnostics( | ||
| model.getValue(), | ||
| enableTypeCheckRef.current, | ||
| ); |
There was a problem hiding this comment.
When enableTypeCheckRef.current is true, mq.diagnostics can return type-check diagnostics whose startLine/endLine are 0-based (see crates/mq-wasm/src/script.rs where type error lines are line.saturating_sub(1)), while parse diagnostics appear to be 1-based. Monaco markers are 1-based, so type-check errors may be rendered on the wrong line or not at all. Normalize diagnostic line numbers before calling setModelMarkers (or fix the wasm side to consistently return 1-based positions).
| <input | ||
| type="checkbox" | ||
| checked={enableTypeCheck} | ||
| onChange={(e) => setEnableTypeCheck(e.target.checked)} |
There was a problem hiding this comment.
Toggling the Type Check checkbox only updates state/localStorage; it doesn’t trigger a diagnostics recompute or an inlay-hints refresh, so users may keep seeing stale markers/hints until they type again. Consider triggering a markers refresh + inlay-hints refresh when enableTypeCheck changes (e.g., keep a Monaco editor/model ref and re-run diagnostics / call Monaco’s inlay hints refresh action).
| onChange={(e) => setEnableTypeCheck(e.target.checked)} | |
| onChange={(e) => { | |
| const enabled = e.target.checked; | |
| setEnableTypeCheck(enabled); | |
| // Force diagnostics and inlay hints to refresh immediately | |
| // when the type-checking setting changes. This avoids | |
| // stale markers/hints persisting until the next edit. | |
| const editors = (editor as typeof editor & { | |
| getEditors?: () => editor.IStandaloneCodeEditor[]; | |
| }).getEditors | |
| ? (editor as typeof editor & { | |
| getEditors: () => editor.IStandaloneCodeEditor[]; | |
| }).getEditors() | |
| : []; | |
| editors.forEach((instance) => { | |
| const model = instance.getModel(); | |
| if (!model) { | |
| return; | |
| } | |
| const value = model.getValue(); | |
| // Writing the same value back triggers Monaco's | |
| // validation / diagnostics pipeline without changing | |
| // the visible content. | |
| model.setValue(value); | |
| const action = | |
| instance.getAction?.("editor.action.inlineHints"); | |
| action?.run(); | |
| }); | |
| }} |
8e71666 to
76bebe9
Compare
No description provided.