diff --git a/actions-workflow-parser/src/expressions.test.ts b/actions-workflow-parser/src/expressions.test.ts index 8bdc916..c8f1664 100644 --- a/actions-workflow-parser/src/expressions.test.ts +++ b/actions-workflow-parser/src/expressions.test.ts @@ -55,7 +55,7 @@ jobs: steps: - run: | echo \${{ github.event_name }} - echo 'hello' \${{ github.ref }}` + echo 'hello' \${{github.ref }}` } ], nullTrace @@ -81,19 +81,27 @@ jobs: } expect(stepRun.originalExpressions).toHaveLength(2); - expect(stepRun.originalExpressions!.map(x => [x.toDisplayString(), x.range])).toEqual([ + expect(stepRun.originalExpressions!.map(x => [x.toDisplayString(), x.range, x.expressionRange])).toEqual([ [ "${{ github.event_name }}", { start: {line: 7, column: 16}, end: {line: 7, column: 40} + }, + { + start: {line: 7, column: 20}, + end: {line: 7, column: 37} } ], [ "${{ github.ref }}", { start: {line: 8, column: 24}, - end: {line: 8, column: 41} + end: {line: 8, column: 40} + }, + { + start: {line: 8, column: 27}, + end: {line: 8, column: 37} } ] ]); diff --git a/actions-workflow-parser/src/model/converter/jobs.ts b/actions-workflow-parser/src/model/converter/jobs.ts index 17aa165..ac31142 100644 --- a/actions-workflow-parser/src/model/converter/jobs.ts +++ b/actions-workflow-parser/src/model/converter/jobs.ts @@ -111,7 +111,7 @@ function convertJob(context: TemplateContext, jobKey: StringToken, token: Mappin id: jobKey, name: undefined, needs: undefined, - if: new BasicExpressionToken(undefined, undefined, "success()", undefined, undefined), + if: new BasicExpressionToken(undefined, undefined, "success()", undefined, undefined, undefined), env: undefined, concurrency: undefined, environment: undefined, diff --git a/actions-workflow-parser/src/model/converter/steps.ts b/actions-workflow-parser/src/model/converter/steps.ts index 4adca20..aa11f5d 100644 --- a/actions-workflow-parser/src/model/converter/steps.ts +++ b/actions-workflow-parser/src/model/converter/steps.ts @@ -52,7 +52,7 @@ function convertStep(context: TemplateContext, idBuilder: IdBuilder, step: Templ let uses: StringToken | undefined; let continueOnError: boolean | undefined; let env: MappingToken | undefined; - const ifCondition = new BasicExpressionToken(undefined, undefined, "success()", undefined, undefined); + const ifCondition = new BasicExpressionToken(undefined, undefined, "success()", undefined, undefined, undefined); for (const item of mapping) { const key = item.key.assertString("steps item key"); switch (key.value) { diff --git a/actions-workflow-parser/src/templates/template-reader.ts b/actions-workflow-parser/src/templates/template-reader.ts index d00ea75..cdc3e4c 100644 --- a/actions-workflow-parser/src/templates/template-reader.ts +++ b/actions-workflow-parser/src/templates/template-reader.ts @@ -607,7 +607,8 @@ class TemplateReader { token.range, `format('${format.join("")}'${args.join("")})`, token.definitionInfo, - expressionTokens + expressionTokens, + undefined ); } @@ -615,10 +616,10 @@ class TemplateReader { tr: TokenRange, rawExpression: string, allowedContext: string[], - token: TemplateToken, + token: StringToken, definitionInfo: DefinitionInfo | undefined ): ExpressionToken | undefined { - const parseExpressionResult = this.parseExpression(tr, rawExpression, allowedContext, definitionInfo); + const parseExpressionResult = this.parseExpression(tr, token, rawExpression, allowedContext, definitionInfo); // Check for error if (parseExpressionResult.error) { @@ -630,7 +631,8 @@ class TemplateReader { } private parseExpression( - range: TokenRange | undefined, + range: TokenRange, + token: StringToken, value: string, allowedContext: string[], definitionInfo: DefinitionInfo | undefined @@ -665,9 +667,31 @@ class TemplateReader { }; } + const startTrim = value.length - value.trimStart().length; + const endTrim = value.length - value.trimEnd().length; + + const expressionRange: TokenRange = { + start: { + ...range.start, + column: range.start.column + OPEN_EXPRESSION.length + startTrim + }, + end: { + ...range.end, + column: range.end.column - CLOSE_EXPRESSION.length - endTrim + } + }; + // Return the expression return { - expression: new BasicExpressionToken(this._fileId, range, trimmed, definitionInfo, undefined), + expression: new BasicExpressionToken( + this._fileId, + range, + trimmed, + definitionInfo, + undefined, + token.source, + expressionRange + ), error: undefined }; } diff --git a/actions-workflow-parser/src/templates/tokens/basic-expression-token.ts b/actions-workflow-parser/src/templates/tokens/basic-expression-token.ts index 6d5912d..01c7a44 100644 --- a/actions-workflow-parser/src/templates/tokens/basic-expression-token.ts +++ b/actions-workflow-parser/src/templates/tokens/basic-expression-token.ts @@ -11,8 +11,18 @@ import {TokenType} from "./types"; export class BasicExpressionToken extends ExpressionToken { private readonly expr: string; + public readonly source: string | undefined; + public readonly originalExpressions: BasicExpressionToken[] | undefined; + /** + * The range of the expression within the source string. + * + * `range` is the range of the entire expression, including the `${{` and `}}`. `expression` is only the expression + * without any ${{ }} markers. `expressionRange` is the range of just the expression within the document. + */ + public readonly expressionRange: TokenRange | undefined; + /** * @param originalExpressions If the basic expression was transformed from individual expressions, these will be the original ones */ @@ -21,11 +31,15 @@ export class BasicExpressionToken extends ExpressionToken { range: TokenRange | undefined, expression: string, definitionInfo: DefinitionInfo | undefined, - originalExpressions: BasicExpressionToken[] | undefined + originalExpressions: BasicExpressionToken[] | undefined, + source: string | undefined, + expressionRange?: TokenRange | undefined ) { super(TokenType.BasicExpression, file, range, undefined, definitionInfo); this.expr = expression; + this.source = source; this.originalExpressions = originalExpressions; + this.expressionRange = expressionRange; } public get expression(): string { @@ -34,8 +48,24 @@ export class BasicExpressionToken extends ExpressionToken { public override clone(omitSource?: boolean): TemplateToken { return omitSource - ? new BasicExpressionToken(undefined, undefined, this.expr, this.definitionInfo, this.originalExpressions) - : new BasicExpressionToken(this.file, this.range, this.expr, this.definitionInfo, this.originalExpressions); + ? new BasicExpressionToken( + undefined, + undefined, + this.expr, + this.definitionInfo, + this.originalExpressions, + this.source, + this.expressionRange + ) + : new BasicExpressionToken( + this.file, + this.range, + this.expr, + this.definitionInfo, + this.originalExpressions, + this.source, + this.expressionRange + ); } public override toString(): string { diff --git a/actions-workflow-parser/src/templates/tokens/token-range.ts b/actions-workflow-parser/src/templates/tokens/token-range.ts index 03d5f8e..8cc0c2b 100644 --- a/actions-workflow-parser/src/templates/tokens/token-range.ts +++ b/actions-workflow-parser/src/templates/tokens/token-range.ts @@ -2,6 +2,7 @@ export type Position = { /** The one-based line value */ line: number; + /** The one-based column value */ column: number; };