Skip to content

Add diagnosticsOptions option for languages#59

Merged
ije merged 6 commits intomainfrom
add-lsp-validate-option
Mar 2, 2026
Merged

Add diagnosticsOptions option for languages#59
ije merged 6 commits intomainfrom
add-lsp-validate-option

Conversation

@ije
Copy link
Member

@ije ije commented Mar 2, 2026

this pr adds feature allow you to set the diagnostics options for all languages by adding the diagnosticsOptions option to the lsp options:

lazy({
  lsp: {
    css: {
      diagnosticsOptions: {
        // filter out unknown property errors
        filter: (diagnostic) => diagnostic.code !== "unknownProperty"
      }
    },
    json: {
      diagnosticsOptions: {
        // disable syntax and semantic validation
        validate: false
      }
    },
    typescript: {
      diagnosticsOptions: {
        // ignore type not found errors (code 2307)
        codesToIgnore: [2307],
      }
    }
  }
})

close #57

Copilot AI review requested due to automatic review settings March 2, 2026 02:30
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a per-language diagnosticsOptions configuration surface to the built-in LSP integrations so consumers can disable validation and/or filter/ignore specific diagnostics (e.g., disable CSS validation while keeping completion/hover).

Changes:

  • Introduces diagnosticsOptions (validate / codesToIgnore / filter) and wires it through the LSP client’s diagnostics registration.
  • Extends HTML/CSS/JSON/TypeScript language setup to accept typed settings and pass diagnostics options; adds CSS validProperties helper and richer HTML/CSS data provider typing.
  • Updates workspace document opening flow and adds new examples + README updates.

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
types/lsp.d.ts Expands public LSP config/types (data providers, CSS valid properties, diagnosticsOptions) and related data model types.
src/lsp/client.ts Adds diagnostics options handling (skip validation, filter markers, ignore codes).
src/lsp/css/setup.ts Passes diagnostics options into basic features; adds validProperties → custom data provider wiring.
src/lsp/css/worker.ts Renames CSS data config interface used by worker create data.
src/lsp/html/setup.ts Adds typed HTML settings, supports custom data providers and diagnostics options.
src/lsp/json/setup.ts Adds typed JSON settings and uses diagnostics options for validation + passes through to diagnostics registration.
src/lsp/typescript/setup.ts Types TS language settings and passes diagnostics options to diagnostics registration; updates workspace model open call signature.
src/workspace.ts Changes _openTextDocument to accept monaco explicitly; modifies openTextDocument editor selection logic.
src/core.ts Updates internal calls to _openTextDocument to pass monaco.
scripts/dev.ts Adds dev-server links for new examples.
examples/with-diagnostics-options.html Demonstrates filtering/ignoring diagnostics and disabling validation via diagnosticsOptions.
examples/css-valid-properites.html Demonstrates CSS validProperties usage.
README.md Documents the new configuration options and provides usage examples.
Comments suppressed due to low confidence (1)

src/lsp/json/setup.ts:37

  • validate is set from diagnosticsOptions and then ...languageSettings is spread afterwards, which can overwrite validate (e.g. if languageSettings still contains validate for backward-compat). If diagnosticsOptions.validate is intended to be authoritative, spread languageSettings first and then set validate last (or explicitly omit validate from the spread).
    settings: {
      validate: languageSettings?.diagnosticsOptions?.validate ?? true,
      allowComments: false,
      comments: "error",
      trailingCommas: "error",
      schemaRequest: "warning",
      schemaValidation: "warning",
      ...languageSettings,
      schemas,

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

src/workspace.ts Outdated
Comment on lines 100 to 107
const getEditor = async () => {
const editors = monaco.editor.getEditors();
if (editors.length === 0) {
return new Promise<monacoNS.editor.ICodeEditor>((resolve) => setTimeout(() => resolve(getEditor()), 100));
}
return editors[0];
};
return this._openTextDocument(monaco, uri, await getEditor(), undefined, content);
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

openTextDocument() now waits until at least one editor exists. Since _openTextDocument() already supports editor being undefined, this can cause openTextDocument() to hang forever in scenarios where no editor is created (e.g. headless usage / tests / custom embedding). Consider passing monaco.editor.getEditors()[0] directly (possibly undefined), or add a bounded timeout / explicit opt-in wait behavior.

Suggested change
const getEditor = async () => {
const editors = monaco.editor.getEditors();
if (editors.length === 0) {
return new Promise<monacoNS.editor.ICodeEditor>((resolve) => setTimeout(() => resolve(getEditor()), 100));
}
return editors[0];
};
return this._openTextDocument(monaco, uri, await getEditor(), undefined, content);
const editors = monaco.editor.getEditors();
const editor = editors.length > 0 ? editors[0] : undefined;
return this._openTextDocument(monaco, uri, editor, undefined, content);

Copilot uses AI. Check for mistakes.
Comment on lines 22 to 27
const validProperties = languageSettings?.validProperties;
if (validProperties) {
languageSettings.dataProviders = {
"valid-properties": {
version: 1.1,
properties: validProperties.map(property => ({ name: property })),
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block mutates the caller-provided languageSettings object by assigning to languageSettings.dataProviders. That can be surprising if the same settings object is reused across calls. Prefer building a local dataProviders object and passing it into createData without mutating the input.

Copilot uses AI. Check for mistakes.
version: 1.1,
properties: validProperties.map(property => ({ name: property })),
},
...(languageSettings.dataProviders as Record<string, unknown> | undefined),
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spreading languageSettings.dataProviders via as Record<string, unknown> weakens type safety and can mask non-object values at compile time. Since dataProviders is already typed as an object map, prefer ...(languageSettings.dataProviders ?? {}) (or clone first) to avoid the cast.

Suggested change
...(languageSettings.dataProviders as Record<string, unknown> | undefined),
...(languageSettings.dataProviders ?? {}),

Copilot uses AI. Check for mistakes.
README.md Outdated
Comment on lines 444 to 448
You can also set the diagnostics options for all languages by adding the `diagnosticsOptions` option to the `lsp` object:

```js
lazy({
lsp: {
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The text says diagnostics options can be set "for all languages" by adding diagnosticsOptions to the lsp object, but the example only shows per-language diagnosticsOptions and the types don’t define a top-level lsp.diagnosticsOptions. Either adjust the wording to “for each language” (or similar), or add/implement a true global lsp.diagnosticsOptions that is applied by default.

Copilot uses AI. Check for mistakes.
scripts/dev.ts Outdated
Multiple themes - ${server.url}multi-theme
SSR mode - ${server.url}ssr
Compare modes - ${server.url}compare
CSS valid properties - ${server.url}css-valid-properites
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in example URL: css-valid-properites -> css-valid-properties (and rename the example file accordingly). Keeping the typo makes the dev server output and routes harder to discover/remember.

Suggested change
CSS valid properties - ${server.url}css-valid-properites
CSS valid properties - ${server.url}css-valid-properties

Copilot uses AI. Check for mistakes.
Comment on lines 18 to 19
/** Configures the CSS data types known by the langauge service. */
readonly data?: CSSDataConfiguration;
readonly data?: CSSLanguageServiceOptions;
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling in comment: langauge -> language.

Copilot uses AI. Check for mistakes.
) {
const { editor, languages } = monaco;
const { tabSize, insertSpaces, insertFinalNewline, trimFinalNewlines } = formattingOptions ?? {};
const dataProviders = languageSettings?.dataProviders ?? {};
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dataProviders is assigned from languageSettings?.dataProviders and then mutated by adding custom-tags. This mutates the caller-provided object, which can create surprising side effects if the same settings object is reused. Consider cloning ({ ...languageSettings?.dataProviders }) before adding derived providers.

Suggested change
const dataProviders = languageSettings?.dataProviders ?? {};
const dataProviders = { ...(languageSettings?.dataProviders ?? {}) };

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 14 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +133 to +139
const editors = monaco.editor.getEditors();
const editor = editors.find(e => e.hasWidgetFocus() || e.hasTextFocus()) ?? editors[0];
if (editor) {
await workspace._openTextDocument(monaco, editor, uri);
return true;
}
return false;
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Host.openModel is invoked by the TypeScript worker during module resolution (imports). Calling workspace._openTextDocument(monaco, editor, uri) here will switch the visible editor model and push workspace history for every imported file, which is likely to cause unexpected navigation/focus changes while typing. openModel should create/sync the model without mutating any editor instance (e.g., allow _openTextDocument to accept editor as optional/undefined and skip editor.setModel/history updates, or add a dedicated internal method for background model creation).

Suggested change
const editors = monaco.editor.getEditors();
const editor = editors.find(e => e.hasWidgetFocus() || e.hasTextFocus()) ?? editors[0];
if (editor) {
await workspace._openTextDocument(monaco, editor, uri);
return true;
}
return false;
// Ensure the model for the given URI is created/synced without mutating any editor instance.
await workspace._openTextDocument(monaco, undefined as never, uri);
return true;

Copilot uses AI. Check for mistakes.
Comment on lines 71 to 85
// register language features
client.registerEmbedded(languageId, workerWithEmbeddedLanguages, ["css", "javascript", "importmap"]);
client.registerBasicFeatures(languageId, workerWithEmbeddedLanguages, ["<", "/", "=", '"'], workspace);
client.registerBasicFeatures(
languageId,
workerWithEmbeddedLanguages,
["<", "/", "=", '"'],
workspace,
languageSettings?.diagnosticsOptions,
);
client.registerAutoComplete(languageId, workerWithEmbeddedLanguages, [">", "/", "="]);
client.registerColorPresentation(languageId, workerWithEmbeddedLanguages); // css color presentation
client.registerDocumentLinks(languageId, workerWithEmbeddedLanguages);

// support embedded languages(css, javascript and importmap) in html files
client.registerEmbedded(languageId, workerWithEmbeddedLanguages, ["css", "javascript", "importmap"]);

Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

registerBasicFeatures() triggers an immediate diagnostics run over existing models. Because registerEmbedded() is called afterwards, embedded models for css/javascript/importmap may not exist yet during the first validation pass, so initial embedded diagnostics can be missing until the user edits. Consider registering embedded-language support before enabling diagnostics, or explicitly triggering a refreshDiagnostics on the master HTML model after registerEmbedded has created/updated embedded models.

Copilot uses AI. Check for mistakes.
Comment on lines +98 to +108
async openTextDocument(uri: string | URL, content?: string, editor?: any): Promise<monacoNS.editor.ITextModel> {
const monaco = await this._monaco.promise;
return this._openTextDocument(uri, monaco.editor.getEditors()[0], undefined, content);
const getEditor = async () => {
const editors = monaco.editor.getEditors();
const editor = editors.find(e => e.hasWidgetFocus() || e.hasTextFocus()) ?? editors[0];
if (!editor) {
return new Promise<monacoNS.editor.ICodeEditor>((resolve) => setTimeout(() => resolve(getEditor()), 100));
}
return editor;
};
return this._openTextDocument(monaco, editor ?? await getEditor(), uri, undefined, content);
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

openTextDocument takes editor?: any, but the public typings expose this parameter as editor.ICodeEditor. Using any here removes type safety and makes it easy to pass the wrong shape. Please type this parameter as monacoNS.editor.ICodeEditor | undefined (or ICodeEditor | null if you want an explicit sentinel) and adjust downstream calls accordingly.

Copilot uses AI. Check for mistakes.
Comment on lines 413 to 431
@@ -418,17 +426,48 @@ export interface LSPConfig {
schemaValidation?: SeverityLevel;
/** The severity of problems that occurred when resolving and loading schemas. Default is "warning". */
schemaRequest?: SeverityLevel;
/** Options for the diagnostics. */
diagnosticsOptions?: DiagnosticsOptions;
};
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README previously documented lsp.json.validate as the way to disable JSON validation, but the config shape shown here now only exposes json.diagnosticsOptions.validate. If this is an intentional breaking change, it should be called out with a short migration note (or keep json.validate documented as a deprecated alias) to avoid silently breaking existing integrations.

Copilot uses AI. Check for mistakes.
@ije ije merged commit 6b5b89e into main Mar 2, 2026
@ije ije deleted the add-lsp-validate-option branch March 2, 2026 06:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: CSS validate: false option

2 participants