Files
languageservices/actions-languageservice/src/expression-hover/visitor.test.ts
T
2023-02-02 08:57:02 -08:00

135 lines
4.2 KiB
TypeScript

import {data, DescriptionDictionary, Lexer, Parser} from "@github/actions-expressions";
import {convertWorkflowTemplate, parseWorkflow} from "@github/actions-workflow-parser";
import {ErrorPolicy} from "@github/actions-workflow-parser/model/convert";
import {File} from "@github/actions-workflow-parser/workflows/file";
import {ContextProviderConfig} from "../context-providers/config";
import {getContext, Mode} from "../context-providers/default";
import {getWorkflowContext} from "../context/workflow-context";
import {validatorFunctions} from "../expression-validation/functions";
import {nullTrace} from "../nulltrace";
import {getPositionFromCursor} from "../test-utils/cursor-position";
import {HoverVisitor} from "./visitor";
const contextProviderConfig: ContextProviderConfig = {
getContext: async (context: string) => {
switch (context) {
case "github":
return new DescriptionDictionary(
{
key: "event",
value: new data.StringData("push"),
description: "The event that triggered the workflow"
},
{
key: "test",
value: new DescriptionDictionary({
key: "name",
value: new data.StringData("push"),
description: "Name for the test"
}),
description: "Test dictionary"
}
);
}
return undefined;
}
};
describe("visitor", () => {
describe("unsupported hover positions", () => {
["1 =|= 2", "12|3", "1 == |(2)", "'ab|c'"].forEach(x =>
it(x, async () => expect(await hoverExpression(x)).toBeUndefined())
);
});
it("top-level context access", async () => {
expect(await hoverExpression("githu|b")).toEqual({
label: "github",
description:
"Information about the workflow run. For more information, see [`github` context](https://docs.github.com/actions/learn-github-actions/contexts#github-context).",
function: false,
range: {
start: {line: 0, column: 0},
end: {line: 0, column: 6}
}
});
});
it("nested context access", async () => {
expect(await hoverExpression("github.test.na|me")).toEqual({
label: "name",
description: "Name for the test",
function: false,
range: {
start: {line: 0, column: 0},
end: {line: 0, column: 16}
}
});
});
it("nested context access with string key", async () => {
expect(await hoverExpression("github['te|st']")).toEqual({
label: "test",
description: "Test dictionary",
function: false,
range: {
start: {line: 0, column: 0},
end: {line: 0, column: 13}
}
});
});
it("function call", async () => {
expect(await hoverExpression("cont|ains(github, 'github')")).toEqual({
label: "contains",
description:
"`contains( search, item )`\n\nReturns `true` if `search` contains `item`. If `search`" +
" is an array, this function returns `true` if the `item` is an element in the array. If `search`" +
" is a string, this function returns `true` if the `item` is a substring of `search`. This function" +
" is not case sensitive. Casts values to a string.",
function: true,
range: {
start: {line: 0, column: 0},
end: {line: 0, column: 8}
}
});
});
});
async function hoverExpression(input: string) {
const [td, pos] = getPositionFromCursor(input);
const allowedContext = ["github"]; //token.definitionInfo?.allowedContext || [];
const file: File = {
name: td.uri,
content: td.getText()
};
const result = parseWorkflow(file.name, [file], nullTrace);
if (!result.value) {
return undefined;
}
const template = convertWorkflowTemplate(result.context, result.value, ErrorPolicy.TryConversion);
const workflowContext = getWorkflowContext(td.uri, template, []);
const context = await getContext(allowedContext, contextProviderConfig, workflowContext, Mode.Completion);
const r = new HoverVisitor(
{
line: pos.line,
column: pos.character
},
context,
[],
validatorFunctions
);
const l = new Lexer(td.getText());
const lr = l.lex();
const p = new Parser(lr.tokens, ["github"], []);
const expr = p.parse();
return r.hover(expr);
}