Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions apps/oxlint/test/lsp/lint/__snapshots__/lint.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`LSP linting > basic linting > should handle default/test.ts 1`] = `
"--- FILE -----------
default/test.ts
--- Diagnostics ---------
> 1 | debugger;
| ^^^^^^^^^ Warning: \`debugger\` statement is not allowed
help: Remove the debugger statement
2 |
--------------------"
`;

exports[`LSP linting > basic linting > should handle default/test.tsx 1`] = `
"--- FILE -----------
default/test.tsx
--- Diagnostics ---------
> 1 | debugger;
| ^^^^^^^^^ Warning: \`debugger\` statement is not allowed
help: Remove the debugger statement
2 |
--------------------"
`;

exports[`LSP linting > config options > should apply config from config-default/test.ts 1`] = `
"--- FILE -----------
config-default/test.ts
--- Diagnostics ---------
> 1 | debugger;
| ^^^^^^^^^ Warning: \`debugger\` statement is not allowed
help: Remove the debugger statement
2 |
--------------------"
`;

exports[`LSP linting > config options > should apply config from config-disabled/test.ts 1`] = `
"--- FILE -----------
config-disabled/test.ts
--- Diagnostics ---------

--------------------"
`;

exports[`LSP linting > config options > should apply config from config-js-plugin/test.js 1`] = `
"--- FILE -----------
config-js-plugin/test.js
--- Diagnostics ---------
> 1 | debugger;
| ^^^^^^^^^ Error: Custom name JS Plugin Test Rule.
2 |
--------------------"
`;

exports[`LSP linting > config options > should apply config from config-severity/test.ts 1`] = `
"--- FILE -----------
config-severity/test.ts
--- Diagnostics ---------
> 1 | debugger;
| ^^^^^^^^^ Error: \`debugger\` statement is not allowed
help: Remove the debugger statement
2 |
--------------------"
`;

exports[`LSP linting > initializationOptions > should use custom config path from configPath 1`] = `
"--- FILE -----------
custom-config-path/test.ts
--- Diagnostics ---------
> 1 | debugger;
| ^^^^^^^^^ Error: \`debugger\` statement is not allowed
help: Remove the debugger statement
2 |
--------------------"
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
debugger;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"no-debugger": "off"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
debugger;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"jsPlugins": ["./plugin.js"],
"rules": {
"js-plugin/test-rule": "error",
"no-debugger": "off",
}
}
22 changes: 22 additions & 0 deletions apps/oxlint/test/lsp/lint/fixtures/config-js-plugin/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const plugin = {
meta: {
name: 'js-plugin',
},
rules: {
'test-rule': {
create(context) {
return {
DebuggerStatement(debuggerStatement) {
context.report({
message: 'Custom name JS Plugin Test Rule.',
node: debuggerStatement,
});
},
};
},
},
},
};


export default plugin;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
debugger;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"no-debugger": "error"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
debugger;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"no-debugger": "error"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
debugger;
1 change: 1 addition & 0 deletions apps/oxlint/test/lsp/lint/fixtures/default/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
debugger;
1 change: 1 addition & 0 deletions apps/oxlint/test/lsp/lint/fixtures/default/test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
debugger;
37 changes: 37 additions & 0 deletions apps/oxlint/test/lsp/lint/lint.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { lintFixture } from "../utils";

const FIXTURES_DIR = join(import.meta.dirname, "fixtures");

describe("LSP linting", () => {
describe("basic linting", () => {
it.each([
["default/test.tsx", "typescriptreact"],
["default/test.ts", "typescript"],
])("should handle %s", async (path, languageId) => {
expect(await lintFixture(FIXTURES_DIR, path, languageId)).toMatchSnapshot();
});
});

describe("config options", () => {
it.each([
["config-default/test.ts", "typescript"],
["config-disabled/test.ts", "typescript"],
["config-severity/test.ts", "typescript"],
["config-js-plugin/test.js", "javascript"],
])("should apply config from %s", async (path, languageId) => {
expect(await lintFixture(FIXTURES_DIR, path, languageId)).toMatchSnapshot();
});
});

describe("initializationOptions", () => {
it("should use custom config path from configPath", async () => {
expect(
await lintFixture(FIXTURES_DIR, "custom-config-path/test.ts", "typescript", {
configPath: "./lint.json",
}),
).toMatchSnapshot();
});
});
});
47 changes: 41 additions & 6 deletions apps/oxlint/test/lsp/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { dirname, join } from "node:path";
import { pathToFileURL } from "node:url";
import {
createMessageConnection,
DiagnosticSeverity,
DidChangeConfigurationNotification,
DidChangeTextDocumentNotification,
DidOpenTextDocumentNotification,
Expand All @@ -27,7 +28,12 @@ import { codeFrameColumns } from "@babel/code-frame";
const CLI_PATH = join(import.meta.dirname, "..", "..", "dist", "cli.js");

export function createLspConnection() {
const proc = spawn(process.execPath, [CLI_PATH, "--lsp"]);
const proc = spawn(process.execPath, [CLI_PATH, "--lsp"], {
env: {
...process.env,
OXC_LOG: "debug",
},
});

const connection = createMessageConnection(
new StreamMessageReader(proc.stdout),
Expand Down Expand Up @@ -147,14 +153,43 @@ ${applyDiagnostics(content, diagnostics).join("\n--------------------")}

type OxlintLSPConfig = {};

function getSeverityLabel(severity: number | undefined): string {
if (!severity) return "Unknown";

switch (severity) {
case DiagnosticSeverity.Error:
return "Error";
case DiagnosticSeverity.Warning:
return "Warning";
case DiagnosticSeverity.Information:
return "Information";
case DiagnosticSeverity.Hint:
return "Hint";
default:
return "Unknown";
}
}

function applyDiagnostics(content: string, report: DocumentDiagnosticReport): string[] {
if (report.kind !== "full") {
throw new Error("Only full reports are supported by oxlint lsp");
}

return report.items.map((diagnostic) =>
codeFrameColumns(content, diagnostic.range, {
message: diagnostic.message,
}),
);
return report.items.map((diagnostic) => {
const babelLocation = {
start: {
line: diagnostic.range.start.line + 1,
column: diagnostic.range.start.character + 1,
},
end: {
line: diagnostic.range.end.line + 1,
column: diagnostic.range.end.character + 1,
},
};
const severity = getSeverityLabel(diagnostic.severity);

return codeFrameColumns(content, babelLocation, {
message: `${severity}: ${diagnostic.message}`,
});
});
}
2 changes: 2 additions & 0 deletions crates/oxc_language_server/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ impl LanguageServer for Backend {
.map(|workspace_options| workspace_options.options.clone())
.unwrap_or_default();

debug!("starting worker in initialize with options: {option:?}");
worker.start_worker(option).await;
}
}
Expand Down Expand Up @@ -224,6 +225,7 @@ impl LanguageServer for Backend {
for (index, worker) in needed_configurations.values().copied().enumerate() {
// get the configuration from the response and start the worker
let configuration = configurations.get(index).unwrap_or(&serde_json::Value::Null);
debug!("starting worker in initialize with options: {configuration:?}");
worker.start_worker(configuration.clone()).await;

// run diagnostics for all known files in the workspace of the worker.
Expand Down
Loading