React to extracted functions, add test
This commit is contained in:
@@ -153,6 +153,24 @@ describe("expressions", () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("multiple regions - first region", async () => {
|
||||||
|
const input = "run-name: test-${{ git| == 1 }}-${{ github.event }}";
|
||||||
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
||||||
|
|
||||||
|
expect(result.map(x => x.label)).toEqual([
|
||||||
|
"github",
|
||||||
|
"inputs",
|
||||||
|
"vars",
|
||||||
|
"contains",
|
||||||
|
"endsWith",
|
||||||
|
"format",
|
||||||
|
"fromJson",
|
||||||
|
"join",
|
||||||
|
"startsWith",
|
||||||
|
"toJson"
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it("multiple regions", async () => {
|
it("multiple regions", async () => {
|
||||||
const input = "run-name: test-${{ github }}-${{ | }}";
|
const input = "run-name: test-${{ github }}-${{ | }}";
|
||||||
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {DescriptionDictionary, complete as completeExpression} from "@github/actions-expressions";
|
import {complete as completeExpression, DescriptionDictionary} from "@github/actions-expressions";
|
||||||
import {CompletionItem as ExpressionCompletionItem} from "@github/actions-expressions/completion";
|
import {CompletionItem as ExpressionCompletionItem} from "@github/actions-expressions/completion";
|
||||||
import {
|
import {
|
||||||
convertWorkflowTemplate,
|
convertWorkflowTemplate,
|
||||||
@@ -8,8 +8,6 @@ import {
|
|||||||
parseWorkflow
|
parseWorkflow
|
||||||
} from "@github/actions-workflow-parser";
|
} from "@github/actions-workflow-parser";
|
||||||
import {ErrorPolicy} from "@github/actions-workflow-parser/model/convert";
|
import {ErrorPolicy} from "@github/actions-workflow-parser/model/convert";
|
||||||
import {DefinitionType} from "@github/actions-workflow-parser/templates/schema/definition-type";
|
|
||||||
import {StringDefinition} from "@github/actions-workflow-parser/templates/schema/string-definition";
|
|
||||||
import {OPEN_EXPRESSION} from "@github/actions-workflow-parser/templates/template-constants";
|
import {OPEN_EXPRESSION} from "@github/actions-workflow-parser/templates/template-constants";
|
||||||
import {TemplateToken} from "@github/actions-workflow-parser/templates/tokens/index";
|
import {TemplateToken} from "@github/actions-workflow-parser/templates/tokens/index";
|
||||||
import {MappingToken} from "@github/actions-workflow-parser/templates/tokens/mapping-token";
|
import {MappingToken} from "@github/actions-workflow-parser/templates/tokens/mapping-token";
|
||||||
@@ -26,11 +24,12 @@ import {nullTrace} from "./nulltrace";
|
|||||||
import {findToken} from "./utils/find-token";
|
import {findToken} from "./utils/find-token";
|
||||||
import {guessIndentation} from "./utils/indentation-guesser";
|
import {guessIndentation} from "./utils/indentation-guesser";
|
||||||
import {mapRange} from "./utils/range";
|
import {mapRange} from "./utils/range";
|
||||||
|
import {getRelCharOffset} from "./utils/rel-char-pos";
|
||||||
import {transform} from "./utils/transform";
|
import {transform} from "./utils/transform";
|
||||||
|
import {isStringExpression} from "./utils/type-guards";
|
||||||
import {Value, ValueProviderConfig} from "./value-providers/config";
|
import {Value, ValueProviderConfig} from "./value-providers/config";
|
||||||
import {defaultValueProviders} from "./value-providers/default";
|
import {defaultValueProviders} from "./value-providers/default";
|
||||||
import {definitionValues} from "./value-providers/definition";
|
import {definitionValues} from "./value-providers/definition";
|
||||||
import {TokenRange} from "@github/actions-workflow-parser/templates/tokens/token-range";
|
|
||||||
|
|
||||||
export function getExpressionInput(input: string, pos: number): string {
|
export function getExpressionInput(input: string, pos: number): string {
|
||||||
// Find start marker around the cursor position
|
// Find start marker around the cursor position
|
||||||
@@ -79,7 +78,7 @@ export async function complete(
|
|||||||
// expression nodes for invalid expressions and during editing expressions are invalid most of the time.
|
// expression nodes for invalid expressions and during editing expressions are invalid most of the time.
|
||||||
if (token) {
|
if (token) {
|
||||||
const isStringExpressionToken = isStringExpression(token);
|
const isStringExpressionToken = isStringExpression(token);
|
||||||
const isBasicExpressionToken = isBasicExpression(token) && token.isExpression;
|
const isBasicExpressionToken = isBasicExpression(token);
|
||||||
|
|
||||||
if (isStringExpressionToken || isBasicExpressionToken) {
|
if (isStringExpressionToken || isBasicExpressionToken) {
|
||||||
const allowedContext = token.definitionInfo?.allowedContext || [];
|
const allowedContext = token.definitionInfo?.allowedContext || [];
|
||||||
@@ -93,12 +92,14 @@ export async function complete(
|
|||||||
const indentString = " ".repeat(indentation.tabSize);
|
const indentString = " ".repeat(indentation.tabSize);
|
||||||
|
|
||||||
const values = await getValues(token, keyToken, parent, valueProviderConfig, workflowContext, indentString);
|
const values = await getValues(token, keyToken, parent, valueProviderConfig, workflowContext, indentString);
|
||||||
|
|
||||||
let replaceRange: Range | undefined;
|
let replaceRange: Range | undefined;
|
||||||
if (token?.range) {
|
if (token?.range) {
|
||||||
replaceRange = mapRange(token.range);
|
replaceRange = mapRange(token.range);
|
||||||
} else if (!token) {
|
} else if (!token) {
|
||||||
// Not a valid token, create a range from the current position
|
// Not a valid token, create a range from the current position
|
||||||
const line = newDoc.getText({start: {line: position.line, character: 0}, end: position});
|
const line = newDoc.getText({start: {line: position.line, character: 0}, end: position});
|
||||||
|
|
||||||
// Get the length of the current word
|
// Get the length of the current word
|
||||||
const val = line.match(/[\w_-]*$/)?.[0].length || 0;
|
const val = line.match(/[\w_-]*$/)?.[0].length || 0;
|
||||||
replaceRange = Range.create({line: position.line, character: position.character - val}, position);
|
replaceRange = Range.create({line: position.line, character: position.character - val}, position);
|
||||||
@@ -207,21 +208,21 @@ function getExpressionCompletionItems(
|
|||||||
): CompletionItem[] {
|
): CompletionItem[] {
|
||||||
let expressionInput = "";
|
let expressionInput = "";
|
||||||
let currentInput = "";
|
let currentInput = "";
|
||||||
let relCharPos: number = 0;
|
let relCharOffset: number = 0;
|
||||||
|
|
||||||
if (isBasicExpression(token)) {
|
if (isBasicExpression(token)) {
|
||||||
expressionInput = currentInput = token.expression;
|
expressionInput = currentInput = token.expression;
|
||||||
relCharPos = getRelCharPos(token.range!, expressionInput, pos);
|
relCharOffset = getRelCharOffset(token.range!, expressionInput, pos);
|
||||||
} else {
|
} else {
|
||||||
const stringToken = token.assertString("Expected string token for expression completion");
|
const stringToken = token.assertString("Expected string token for expression completion");
|
||||||
currentInput = stringToken.source || stringToken.value;
|
currentInput = stringToken.source || stringToken.value;
|
||||||
relCharPos = getRelCharPos(stringToken.range!, currentInput, pos);
|
relCharOffset = getRelCharOffset(stringToken.range!, currentInput, pos);
|
||||||
expressionInput = (getExpressionInput(currentInput, relCharPos) || "").trim();
|
expressionInput = (getExpressionInput(currentInput, relCharOffset) || "").trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return completeExpression(expressionInput, context, [], validatorFunctions).map(item =>
|
return completeExpression(expressionInput, context, [], validatorFunctions).map(item =>
|
||||||
mapExpressionCompletionItem(item, currentInput[relCharPos])
|
mapExpressionCompletionItem(item, currentInput[relCharOffset])
|
||||||
);
|
);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
error(`Error while completing expression: '${e?.message || "<no details>"}'`);
|
error(`Error while completing expression: '${e?.message || "<no details>"}'`);
|
||||||
@@ -252,23 +253,3 @@ function mapExpressionCompletionItem(item: ExpressionCompletionItem, charAfterPo
|
|||||||
kind: item.function ? CompletionItemKind.Function : CompletionItemKind.Variable
|
kind: item.function ? CompletionItemKind.Function : CompletionItemKind.Variable
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRelCharPos(tokenRange: TokenRange, currentInput: string, pos: Position): number {
|
|
||||||
// Transform the overall position into a node relative position
|
|
||||||
const range = mapRange(tokenRange);
|
|
||||||
if (range.start.line !== range.end.line) {
|
|
||||||
const lines = currentInput.split("\n");
|
|
||||||
const lineDiff = pos.line - range.start.line - 1;
|
|
||||||
const linesBeforeCusor = lines.slice(0, lineDiff);
|
|
||||||
return linesBeforeCusor.join("\n").length + pos.character + 1;
|
|
||||||
} else {
|
|
||||||
return pos.character - range.start.character;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isStringExpression(token: TemplateToken): boolean {
|
|
||||||
const isExpression =
|
|
||||||
token.definition?.definitionType === DefinitionType.String && (token.definition as StringDefinition).isExpression;
|
|
||||||
const containsExpression = isString(token) && token.value.indexOf(OPEN_EXPRESSION) >= 0;
|
|
||||||
return isExpression || containsExpression;
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user