From a9231073fa76a1bb838f4cdf7d3d032c2cbd024d Mon Sep 17 00:00:00 2001 From: 10xtechie Date: Sun, 9 Oct 2022 19:17:03 -0400 Subject: [PATCH] issue#98 - adding initial changes --- src/service/getGherkinDocumentSymbols.ts | 51 +++++++++++++++++++ .../service/getGherkinDocumentSymbols.test.ts | 42 +++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/service/getGherkinDocumentSymbols.ts create mode 100644 test/service/getGherkinDocumentSymbols.test.ts diff --git a/src/service/getGherkinDocumentSymbols.ts b/src/service/getGherkinDocumentSymbols.ts new file mode 100644 index 00000000..e1e7ccfd --- /dev/null +++ b/src/service/getGherkinDocumentSymbols.ts @@ -0,0 +1,51 @@ +import { Expression } from '@cucumber/cucumber-expressions' +import { dialects, Errors } from '@cucumber/gherkin' +import { walkGherkinDocument } from '@cucumber/gherkin-utils' +import { DocumentSymbol } from 'vscode-languageserver-types' + +import { parseGherkinDocument } from '../gherkin/parseGherkinDocument.js' + +export function getGherkinDocumentSymbols(gherkinSource: string): readonly DocumentSymbol[] { + const symbols: DocumentSymbol[] = [] + const lines = gherkinSource.split(/\r?\n/) + const { gherkinDocument, error } = parseGherkinDocument(gherkinSource) + + if (!gherkinDocument?.feature) { + return symbols + } + let inScenarioOutline = false + const dialect = dialects[gherkinDocument.feature.language] + const noStars = (keyword: string) => keyword !== '* ' + const codeKeywords = [...dialect.given, ...dialect.when, ...dialect.then].filter(noStars) + let snippetKeyword = dialect.given.filter(noStars)[0] + + return walkGherkinDocument(gherkinDocument, symbols, { + scenario(scenario, symbols) { + inScenarioOutline = (scenario.examples || []).length > 0 + return symbols + }, + step(step, symbols) { + if (inScenarioOutline) { + return symbols + } + if (codeKeywords.includes(step.keyword)) { + snippetKeyword = step.keyword + } + + if (step.location.column !== undefined) { + const line = step.location.line - 1 + const character = step.location.column - 1 + step.keyword.length + + return symbols.concat(symbols) + } + return symbols + }, + }) +} + +function isUndefined(stepText: string, expressions: readonly Expression[]): boolean { + for (const expression of expressions) { + if (expression.match(stepText)) return false + } + return true +} diff --git a/test/service/getGherkinDocumentSymbols.test.ts b/test/service/getGherkinDocumentSymbols.test.ts new file mode 100644 index 00000000..11286104 --- /dev/null +++ b/test/service/getGherkinDocumentSymbols.test.ts @@ -0,0 +1,42 @@ +import assert from 'assert' +import { DocumentSymbol, SymbolKind } from 'vscode-languageserver-types' + +import { getGherkinDocumentSymbols } from '../../src/service/getGherkinDocumentSymbols.js' + +describe('getGherkinFormattingEdits', () => { + it('returns text Document Symbols from a Gherkin document', () => { + const gherkinSource = `Feature: Hello +Scenario: World +Given something` + const sourceDocumentSymbols = getGherkinDocumentSymbols(gherkinSource) + const featureSymbol: DocumentSymbol[] = [ + { + name: 'Scenario', + detail: 'Feature', + kind: SymbolKind.Field, + range: { + start: { + line: 1, + character: 0, + }, + end: { + line: 3, + character: 15, + }, + }, + selectionRange: { + start: { + line: 1, + character: 0, + }, + end: { + line: 3, + character: 15, + }, + }, + }, + ] + + assert.deepStrictEqual(featureSymbol, sourceDocumentSymbols) + }) +})