This commit is contained in:
Francesco Renzi
2025-11-28 14:57:59 +00:00
parent e5800c8843
commit 73dd3c33c4
11 changed files with 123 additions and 129 deletions
+1 -1
View File
@@ -169,7 +169,7 @@ export function initConnection(connection: Connection) {
return getCodeActions({
uri: params.textDocument.uri,
diagnostics: params.context.diagnostics,
only: params.context.only,
only: params.context.only
});
});
});
+3 -1
View File
@@ -12,7 +12,9 @@ async function getConnection(): Promise<Connection> {
const {createConnection} = await import("vscode-languageserver/node.js");
return createConnection();
} else {
const { BrowserMessageReader, BrowserMessageWriter, createConnection } = await import("vscode-languageserver/browser.js");
const {BrowserMessageReader, BrowserMessageWriter, createConnection} = await import(
"vscode-languageserver/browser.js"
);
const messageReader = new BrowserMessageReader(self);
const messageWriter = new BrowserMessageWriter(self);
return createConnection(messageReader, messageWriter);
+3 -4
View File
@@ -4,7 +4,7 @@ import { quickfixProviders } from "./quickfix";
// Aggregate all providers by kind
const providersByKind: Map<string, CodeActionProvider[]> = new Map([
[CodeActionKind.QuickFix, quickfixProviders],
[CodeActionKind.QuickFix, quickfixProviders]
// [CodeActionKind. Refactor, refactorProviders],
// [CodeActionKind.Source, sourceProviders],
// etc
@@ -23,14 +23,13 @@ export interface CodeActionParams {
export function getCodeActions(params: CodeActionParams, config?: CodeActionConfig): CodeAction[] {
const actions: CodeAction[] = [];
const context: CodeActionContext = {
uri: params.uri,
uri: params.uri
};
// Filter to requested kinds, or use all if none specified
const requestedKinds = params.only;
const kindsToCheck = requestedKinds
? [...providersByKind.keys()].filter(kind =>
requestedKinds.some(requested => kind.startsWith(requested)))
? [...providersByKind.keys()].filter(kind => requestedKinds.some(requested => kind.startsWith(requested)))
: [...providersByKind.keys()];
for (const diagnostic of params.diagnostics) {
@@ -22,11 +22,11 @@ export const addMissingInputsProvider: CodeActionProvider = {
title: `Add missing input${data.missingInputs.length > 1 ? "s" : ""}: ${inputNames}`,
edit: {
changes: {
[context.uri]: edits,
},
},
[context.uri]: edits
}
}
};
},
}
};
function createInputEdits(data: MissingInputsDiagnosticData): TextEdit[] | undefined {
@@ -43,7 +43,7 @@ function createInputEdits(data: MissingInputsDiagnosticData): TextEdit[] | undef
edits.push({
range: {start: data.insertPosition, end: data.insertPosition},
newText: inputLines.map(line => line + "\n").join(""),
newText: inputLines.map(line => line + "\n").join("")
});
} else {
// No `with:` key - use step indentation for `with:`, +2 for inputs
@@ -59,7 +59,7 @@ function createInputEdits(data: MissingInputsDiagnosticData): TextEdit[] | undef
edits.push({
range: {start: data.insertPosition, end: data.insertPosition},
newText,
newText
});
}
@@ -1,6 +1,4 @@
import {CodeActionProvider} from "../types";
import {addMissingInputsProvider} from "./add-missing-inputs";
export const quickfixProviders: CodeActionProvider[] = [
addMissingInputsProvider,
];
export const quickfixProviders: CodeActionProvider[] = [addMissingInputsProvider];
@@ -22,17 +22,17 @@ const validationConfig: ValidationConfig = {
inputs: {
path: {
description: "A list of files to cache",
required: true,
required: true
},
key: {
description: "Cache key",
required: true,
required: true
},
"restore-keys": {
description: "Restore keys",
required: false,
},
},
required: false
}
}
},
"actions/setup-node@v3": {
name: "Setup Node",
@@ -41,15 +41,15 @@ const validationConfig: ValidationConfig = {
"node-version": {
description: "Node version",
required: true,
default: "16",
},
},
},
default: "16"
}
}
}
};
return Promise.resolve(metadata[key]);
},
},
}
}
};
// Point to the source testdata directory
@@ -44,7 +44,7 @@ export function parseMarkers(content: string): Marker[] {
markers.push({
line: i,
message: match[1],
fix: match[2],
fix: match[2]
});
}
}
@@ -89,7 +89,7 @@ export function loadTestCases(testdataDir: string): TestCase[] {
goldenPath,
input,
golden,
markers: parseMarkers(input),
markers: parseMarkers(input)
});
}
}
@@ -136,10 +136,7 @@ export function applyEdits(content: string, edits: TextEdit[]): string {
/**
* Run a single test case
*/
export async function runTestCase(
testCase: TestCase,
validationConfig: ValidationConfig
): Promise<TestResult> {
export async function runTestCase(testCase: TestCase, validationConfig: ValidationConfig): Promise<TestResult> {
const strippedInput = stripMarkers(testCase.input);
const document = TextDocument.create("file:///test.yml", "yaml", 1, strippedInput);
@@ -149,9 +146,7 @@ export async function runTestCase(
// 2. Verify all expected diagnostics are present
const missingDiagnostics: string[] = [];
for (const marker of testCase.markers) {
const found = diagnostics.find(
d => d.range.start.line === marker.line && d.message.includes(marker.message)
);
const found = diagnostics.find(d => d.range.start.line === marker.line && d.message.includes(marker.message));
if (!found) {
missingDiagnostics.push(`line ${marker.line}: "${marker.message}"`);
}
@@ -161,7 +156,9 @@ export async function runTestCase(
return {
name: testCase.name,
passed: false,
error: `Missing expected diagnostics:\n ${missingDiagnostics.join("\n ")}\n\nActual diagnostics:\n ${diagnostics.map(d => `line ${d.range.start.line}: "${d.message}"`).join("\n ")}`,
error: `Missing expected diagnostics:\n ${missingDiagnostics.join(
"\n "
)}\n\nActual diagnostics:\n ${diagnostics.map(d => `line ${d.range.start.line}: "${d.message}"`).join("\n ")}`
};
}
@@ -173,9 +170,7 @@ export async function runTestCase(
continue;
}
const diagnostic = diagnostics.find(
d => d.range.start.line === marker.line && d.message.includes(marker.message)
);
const diagnostic = diagnostics.find(d => d.range.start.line === marker.line && d.message.includes(marker.message));
if (!diagnostic) {
continue; // Already reported above
@@ -183,19 +178,19 @@ export async function runTestCase(
const params: CodeActionParams = {
uri: document.uri,
diagnostics: [diagnostic],
diagnostics: [diagnostic]
};
const actions = getCodeActions(params);
const matchingAction = actions.find(a =>
a.title.toLowerCase().includes(marker.fix!.toLowerCase())
);
const matchingAction = actions.find(a => a.title.toLowerCase().includes(marker.fix!.toLowerCase()));
if (!matchingAction) {
return {
name: testCase.name,
passed: false,
error: `Code action "${marker.fix}" not found for diagnostic on line ${marker.line}.\nAvailable actions: ${actions.map(a => a.title).join(", ") || "(none)"}`,
error: `Code action "${marker.fix}" not found for diagnostic on line ${marker.line}.\nAvailable actions: ${
actions.map(a => a.title).join(", ") || "(none)"
}`
};
}
@@ -203,7 +198,7 @@ export async function runTestCase(
return {
name: testCase.name,
passed: false,
error: `Code action "${marker.fix}" has no edits`,
error: `Code action "${marker.fix}" has no edits`
};
}
@@ -221,12 +216,12 @@ export async function runTestCase(
passed: false,
error: "Output does not match golden file",
expected: expectedOutput,
actual: actualOutput,
actual: actualOutput
};
}
return {
name: testCase.name,
passed: true,
passed: true
};
}
+3 -3
View File
@@ -9,7 +9,7 @@ import { mapRange } from "./utils/range";
import {ValidationConfig} from "./validate";
export const DiagnosticCode = {
MissingRequiredInputs: "missing-required-inputs",
MissingRequiredInputs: "missing-required-inputs"
} as const;
export interface MissingInputsDiagnosticData {
@@ -109,7 +109,7 @@ export async function validateAction(
action,
missingInputs: missingRequiredInputs.map(([name, input]) => ({
name,
default: input.default,
default: input.default
})),
hasWithKey: withKey !== undefined,
withIndent,
@@ -118,7 +118,7 @@ export async function validateAction(
? {line: withToken.range.end.line - 1, character: 0}
: stepToken.range
? {line: stepToken.range.end.line - 1, character: 0}
: { line: 0, character: 0 },
: {line: 0, character: 0}
};
diagnostics.push({