diff --git a/actions-languageservice/src/hover.ts b/actions-languageservice/src/hover.ts index ba272dc..5154db8 100644 --- a/actions-languageservice/src/hover.ts +++ b/actions-languageservice/src/hover.ts @@ -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 {File} from "@github/actions-workflow-parser/workflows/file"; 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 {token, keyToken, parent} = findToken(position, result.value); + const {token} = findToken(position, result.value); if (result.value && token) { return getHover(token); diff --git a/actions-languageservice/src/validate.test.ts b/actions-languageservice/src/validate.test.ts index 53ebffc..d10116e 100644 --- a/actions-languageservice/src/validate.test.ts +++ b/actions-languageservice/src/validate.test.ts @@ -158,4 +158,33 @@ jobs: } } 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); + }); }); diff --git a/actions-languageservice/src/validate.ts b/actions-languageservice/src/validate.ts index 81023e4..4624dd8 100644 --- a/actions-languageservice/src/validate.ts +++ b/actions-languageservice/src/validate.ts @@ -3,7 +3,6 @@ import {Expr} from "@github/actions-expressions/ast"; import { convertWorkflowTemplate, isBasicExpression, - isSequence, isString, parseWorkflow, ParseWorkflowResult, @@ -11,6 +10,7 @@ import { } from "@github/actions-workflow-parser"; import {ErrorPolicy} from "@github/actions-workflow-parser/model/convert"; 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 {StringToken} from "@github/actions-workflow-parser/templates/tokens/string-token"; import {TemplateToken} from "@github/actions-workflow-parser/templates/tokens/template-token"; @@ -114,12 +114,18 @@ async function additionalValidations( valueProviderConfig: ValueProviderConfig | 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 (isBasicExpression(token)) { await validateExpression( diagnostics, token, + validationDefinition, contextProviderConfig, 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 // a value provider is defined for a token and if it is, validate the values match. - if (valueProviderConfig && token.range && token.definition?.key) { - const defKey = token.definition.key; + if (valueProviderConfig && token.range && validationDefinition) { + const defKey = validationDefinition.key; // Try a custom value provider first let valueProvider = valueProviderConfig[defKey]; @@ -141,18 +147,6 @@ async function additionalValidations( const customValues = await valueProvider.get(getProviderContext(documentUri, template, root, token)); 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 (!customValuesMap.has(token.value)) { invalidValue(diagnostics, token, valueProvider.kind); @@ -202,12 +196,13 @@ function getProviderContext( async function validateExpression( diagnostics: Diagnostic[], token: BasicExpressionToken, + definition: Definition | undefined, contextProviderConfig: ContextProviderConfig | undefined, workflowContext: WorkflowContext ) { // Validate the expression for (const expression of token.originalExpressions || [token]) { - const allowedContexts = token.definition?.readerContext || []; + const allowedContexts = definition?.readerContext || []; const {namedContexts, functions} = splitAllowedContext(allowedContexts); let expr: Expr | undefined;