Fix validation with moved definition

This commit is contained in:
Beth Brennan
2022-12-02 14:31:38 -05:00
parent 272e29a775
commit cd0c836769
3 changed files with 43 additions and 19 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
import {isMapping, parseWorkflow} from "@github/actions-workflow-parser"; import {parseWorkflow} from "@github/actions-workflow-parser";
import {TemplateToken} from "@github/actions-workflow-parser/templates/tokens/template-token"; import {TemplateToken} from "@github/actions-workflow-parser/templates/tokens/template-token";
import {File} from "@github/actions-workflow-parser/workflows/file"; import {File} from "@github/actions-workflow-parser/workflows/file";
import {Position, TextDocument} from "vscode-languageserver-textdocument"; import {Position, TextDocument} from "vscode-languageserver-textdocument";
@@ -14,7 +14,7 @@ export async function hover(document: TextDocument, position: Position): Promise
}; };
const result = parseWorkflow(file.name, [file], nullTrace); const result = parseWorkflow(file.name, [file], nullTrace);
const {token, keyToken, parent} = findToken(position, result.value); const {token} = findToken(position, result.value);
if (result.value && token) { if (result.value && token) {
return getHover(token); return getHover(token);
@@ -158,4 +158,33 @@ jobs:
} }
} as Diagnostic); } as Diagnostic);
}); });
it("unknown event type", async () => {
const result = await validate(
createDocument(
"wf.yaml",
`on: [push, check_run, pr]
jobs:
build:
runs-on:
- ubuntu-latest`
),
defaultValueProviders
);
expect(result.length).toBe(1);
expect(result[0]).toEqual({
message: "Unexpected value 'pr'",
range: {
end: {
character: 24,
line: 0
},
start: {
character: 22,
line: 0
}
}
} as Diagnostic);
});
}); });
+12 -17
View File
@@ -3,7 +3,6 @@ import {Expr} from "@github/actions-expressions/ast";
import { import {
convertWorkflowTemplate, convertWorkflowTemplate,
isBasicExpression, isBasicExpression,
isSequence,
isString, isString,
parseWorkflow, parseWorkflow,
ParseWorkflowResult, ParseWorkflowResult,
@@ -11,6 +10,7 @@ import {
} 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 {splitAllowedContext} from "@github/actions-workflow-parser/templates/allowed-context"; import {splitAllowedContext} from "@github/actions-workflow-parser/templates/allowed-context";
import {Definition} from "@github/actions-workflow-parser/templates/schema/definition";
import {BasicExpressionToken} from "@github/actions-workflow-parser/templates/tokens/basic-expression-token"; import {BasicExpressionToken} from "@github/actions-workflow-parser/templates/tokens/basic-expression-token";
import {StringToken} from "@github/actions-workflow-parser/templates/tokens/string-token"; import {StringToken} from "@github/actions-workflow-parser/templates/tokens/string-token";
import {TemplateToken} from "@github/actions-workflow-parser/templates/tokens/template-token"; import {TemplateToken} from "@github/actions-workflow-parser/templates/tokens/template-token";
@@ -114,12 +114,18 @@ async function additionalValidations(
valueProviderConfig: ValueProviderConfig | undefined, valueProviderConfig: ValueProviderConfig | undefined,
contextProviderConfig: ContextProviderConfig | undefined contextProviderConfig: ContextProviderConfig | undefined
) { ) {
for (const token of TemplateToken.traverse(root)) { for (const [parent, token, key] of TemplateToken.traverse(root)) {
// If the token is a value in a pair, use the key definition for validation
// If the token has a parent (map, sequence, etc), use this definition for validation
const validationToken = key || parent || token;
const validationDefinition = validationToken.definition;
// If this is an expression, validate it // If this is an expression, validate it
if (isBasicExpression(token)) { if (isBasicExpression(token)) {
await validateExpression( await validateExpression(
diagnostics, diagnostics,
token, token,
validationDefinition,
contextProviderConfig, contextProviderConfig,
getProviderContext(documentUri, template, root, token) getProviderContext(documentUri, template, root, token)
); );
@@ -127,8 +133,8 @@ async function additionalValidations(
// Allowed values coming from the schema have already been validated. Only check if // Allowed values coming from the schema have already been validated. Only check if
// a value provider is defined for a token and if it is, validate the values match. // a value provider is defined for a token and if it is, validate the values match.
if (valueProviderConfig && token.range && token.definition?.key) { if (valueProviderConfig && token.range && validationDefinition) {
const defKey = token.definition.key; const defKey = validationDefinition.key;
// Try a custom value provider first // Try a custom value provider first
let valueProvider = valueProviderConfig[defKey]; let valueProvider = valueProviderConfig[defKey];
@@ -141,18 +147,6 @@ async function additionalValidations(
const customValues = await valueProvider.get(getProviderContext(documentUri, template, root, token)); const customValues = await valueProvider.get(getProviderContext(documentUri, template, root, token));
const customValuesMap = new Set(customValues.map(x => x.label)); const customValuesMap = new Set(customValues.map(x => x.label));
if (isSequence(token)) {
for (let i = 0; i < token.count; ++i) {
const entry = token.get(i);
if (isString(entry)) {
if (!customValuesMap.has(entry.value)) {
invalidValue(diagnostics, entry, valueProvider.kind);
}
}
}
}
if (isString(token)) { if (isString(token)) {
if (!customValuesMap.has(token.value)) { if (!customValuesMap.has(token.value)) {
invalidValue(diagnostics, token, valueProvider.kind); invalidValue(diagnostics, token, valueProvider.kind);
@@ -202,12 +196,13 @@ function getProviderContext(
async function validateExpression( async function validateExpression(
diagnostics: Diagnostic[], diagnostics: Diagnostic[],
token: BasicExpressionToken, token: BasicExpressionToken,
definition: Definition | undefined,
contextProviderConfig: ContextProviderConfig | undefined, contextProviderConfig: ContextProviderConfig | undefined,
workflowContext: WorkflowContext workflowContext: WorkflowContext
) { ) {
// Validate the expression // Validate the expression
for (const expression of token.originalExpressions || [token]) { for (const expression of token.originalExpressions || [token]) {
const allowedContexts = token.definition?.readerContext || []; const allowedContexts = definition?.readerContext || [];
const {namedContexts, functions} = splitAllowedContext(allowedContexts); const {namedContexts, functions} = splitAllowedContext(allowedContexts);
let expr: Expr | undefined; let expr: Expr | undefined;