From f29ebcf29017f067eb5e88d9e8c31532f8e136de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aslak=20Helles=C3=B8y?= Date: Mon, 9 May 2022 16:15:59 +0100 Subject: [PATCH 1/2] Add Ruby support. Fixes #41 --- CONTRIBUTING.md | 1 + package-lock.json | 303 ++++++++++++++++++ package.json | 1 + scripts/build.js | 5 + src/tree-sitter-node/NodeParserAdapter.ts | 5 + src/tree-sitter/ExpressionBuilder.ts | 7 +- src/tree-sitter/rubyLanguage.ts | 59 ++++ src/tree-sitter/types.ts | 2 +- test/tree-sitter/ExpressionBuilder.test.ts | 5 +- .../testdata/ruby/ParameterTypes.rb | 13 + .../testdata/ruby/StepDefinitions.rb | 8 + 11 files changed, 404 insertions(+), 5 deletions(-) create mode 100644 src/tree-sitter/rubyLanguage.ts create mode 100644 test/tree-sitter/testdata/ruby/ParameterTypes.rb create mode 100644 test/tree-sitter/testdata/ruby/StepDefinitions.rb diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5b764987..6eefbf2f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,6 +25,7 @@ If your contribution is to add support for a new programming language, follow th - If the Cucumber implementation does not support Cucumber Expressions, make `defineParameterTypeQueries` an empty array 6. Add the name of the new language to the `LanguageName` type 7. Update `treeSitterLanguageByName` in `src/tree-sitter/ExpressionBuilder.ts` + 8 Update `src/tree-sitter-node/NodeParserAdaapter.ts` 8. Run tests As you are working on step 1 and 2 - use [tree-sitter playground](https://tree-sitter.github.io/tree-sitter/playground) diff --git a/package-lock.json b/package-lock.json index b9d5da2c..dd7f7b37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "tree-sitter-c-sharp": "0.19.1", "tree-sitter-java": "0.19.1", "tree-sitter-php": "0.19.0", + "tree-sitter-ruby": "0.19.0", "tree-sitter-typescript": "0.20.1", "vscode-languageserver-types": "3.17.0-next.12" }, @@ -4409,6 +4410,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" + }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -6363,6 +6369,154 @@ "nan": "^2.14.0" } }, + "node_modules/tree-sitter-ruby": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/tree-sitter-ruby/-/tree-sitter-ruby-0.19.0.tgz", + "integrity": "sha512-uzASkTuC6wXnnshfDgij/Q9FYWxODCyIKVb0eHVGX9G5Cu5iFPvgJQgWTKIft1zomTjKjD25YIwFUnXnzZf4Ew==", + "hasInstallScript": true, + "dependencies": { + "nan": "^2.14.1", + "prebuild-install": "^5.0.0" + } + }, + "node_modules/tree-sitter-ruby/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tree-sitter-ruby/node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "node_modules/tree-sitter-ruby/node_modules/are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/tree-sitter-ruby/node_modules/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/tree-sitter-ruby/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tree-sitter-ruby/node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/tree-sitter-ruby/node_modules/prebuild-install": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.6.tgz", + "integrity": "sha512-s8Aai8++QQGi4sSbs/M1Qku62PFK49Jm1CbgXklGz4nmHveDq0wzJkg7Na5QbnO1uNH8K7iqx2EQ/mV0MZEmOg==", + "dependencies": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.7.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^3.0.3", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tree-sitter-ruby/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/tree-sitter-ruby/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/tree-sitter-ruby/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/tree-sitter-ruby/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tree-sitter-ruby/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/tree-sitter-typescript": { "version": "0.20.1", "resolved": "https://registry.npmjs.org/tree-sitter-typescript/-/tree-sitter-typescript-0.20.1.tgz", @@ -6747,6 +6901,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-pm-runs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", + "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", + "engines": { + "node": ">=4" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -10222,6 +10384,11 @@ } } }, + "noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" + }, "nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -11681,6 +11848,137 @@ "nan": "^2.14.0" } }, + "tree-sitter-ruby": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/tree-sitter-ruby/-/tree-sitter-ruby-0.19.0.tgz", + "integrity": "sha512-uzASkTuC6wXnnshfDgij/Q9FYWxODCyIKVb0eHVGX9G5Cu5iFPvgJQgWTKIft1zomTjKjD25YIwFUnXnzZf4Ew==", + "requires": { + "nan": "^2.14.1", + "prebuild-install": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "prebuild-install": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.6.tgz", + "integrity": "sha512-s8Aai8++QQGi4sSbs/M1Qku62PFK49Jm1CbgXklGz4nmHveDq0wzJkg7Na5QbnO1uNH8K7iqx2EQ/mV0MZEmOg==", + "requires": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.7.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^3.0.3", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, "tree-sitter-typescript": { "version": "0.20.1", "resolved": "https://registry.npmjs.org/tree-sitter-typescript/-/tree-sitter-typescript-0.20.1.tgz", @@ -11982,6 +12280,11 @@ "is-symbol": "^1.0.3" } }, + "which-pm-runs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", + "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==" + }, "wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", diff --git a/package.json b/package.json index 47983b93..4344c7f3 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "tree-sitter-c-sharp": "0.19.1", "tree-sitter-java": "0.19.1", "tree-sitter-php": "0.19.0", + "tree-sitter-ruby": "0.19.0", "tree-sitter-typescript": "0.20.1", "vscode-languageserver-types": "3.17.0-next.12" } diff --git a/scripts/build.js b/scripts/build.js index dd9834db..f0fc470f 100755 --- a/scripts/build.js +++ b/scripts/build.js @@ -25,6 +25,11 @@ const languages = [ dir: '', wasm: 'php', }, + { + npm: 'tree-sitter-ruby', + dir: '', + wasm: 'ruby', + }, ] // Build wasm parsers for supported languages diff --git a/src/tree-sitter-node/NodeParserAdapter.ts b/src/tree-sitter-node/NodeParserAdapter.ts index 0a85d31d..4bb38419 100644 --- a/src/tree-sitter-node/NodeParserAdapter.ts +++ b/src/tree-sitter-node/NodeParserAdapter.ts @@ -6,6 +6,8 @@ import Java from 'tree-sitter-java' // @ts-ignore import Php from 'tree-sitter-php' // @ts-ignore +import Ruby from 'tree-sitter-ruby' +// @ts-ignore import TypeScript from 'tree-sitter-typescript' import { LanguageName, ParserAdapter } from '../tree-sitter/types.js' @@ -31,6 +33,9 @@ export class NodeParserAdapter implements ParserAdapter { case 'php': this.parser.setLanguage(Php) break + case 'ruby': + this.parser.setLanguage(Ruby) + break default: throw new Error(`Unsupported language: ${language}`) } diff --git a/src/tree-sitter/ExpressionBuilder.ts b/src/tree-sitter/ExpressionBuilder.ts index fa8149ae..b0e69a0e 100644 --- a/src/tree-sitter/ExpressionBuilder.ts +++ b/src/tree-sitter/ExpressionBuilder.ts @@ -9,6 +9,7 @@ import Parser from 'tree-sitter' import { csharpLanguage } from './csharpLanguage.js' import { javaLanguage } from './javaLanguage.js' import { phpLanguage } from './phpLanguage.js' +import { rubyLanguage } from './rubyLanguage.js' import { LanguageName, ParameterTypeMeta, @@ -23,6 +24,7 @@ const treeSitterLanguageByName: Record = { typescript: typescriptLanguage, c_sharp: csharpLanguage, php: phpLanguage, + ruby: rubyLanguage, } const defineStepDefinitionQueryKeys = ['expression'] @@ -80,9 +82,8 @@ export class ExpressionBuilder { for (const record of records) { const expression = record['expression'] if (expression) { - expressions.push( - expressionFactory.createExpression(treeSitterLanguage.toStringOrRegExp(expression)) - ) + const stringOrRegexp = treeSitterLanguage.toStringOrRegExp(expression) + expressions.push(expressionFactory.createExpression(stringOrRegexp)) } } } diff --git a/src/tree-sitter/rubyLanguage.ts b/src/tree-sitter/rubyLanguage.ts new file mode 100644 index 00000000..3cba5f95 --- /dev/null +++ b/src/tree-sitter/rubyLanguage.ts @@ -0,0 +1,59 @@ +import { TreeSitterLanguage } from './types.js' + +export const rubyLanguage: TreeSitterLanguage = { + defineParameterTypeQueries: [ + ` +(call + method: (constant) @method + arguments: (argument_list + [ + ( + (pair + key: (hash_key_symbol) @name-key + value: (string) @name + ) + (pair + key: (hash_key_symbol) @regexp-key + value: (regex) @expression + ) + ) + ( + (pair + key: (hash_key_symbol) @regexp-key + value: (regex) @expression + ) + (pair + key: (hash_key_symbol) @name-key + value: (string) @name + ) + ) + ] + ) + (#eq? @method "ParameterType") + (#eq? @name-key "name") + (#eq? @regexp-key "regexp") +) +`, + ], + defineStepDefinitionQueries: [ + ` +(call + method: (constant) @method + arguments: (argument_list + [ + (string) @expression + (regex) @expression + ] + ) + (#match? @method "(Given|When|Then)$") +) +`, + ], + + toStringOrRegExp(s: string): string | RegExp { + const match = s.match(/^([/'"])(.*)([/'"])$/) + if (!match) throw new Error(`Could not match '${s}'`) + if (match[1] === '/' && match[3] === '/') return new RegExp(match[2]) + return match[2] + }, +} diff --git a/src/tree-sitter/types.ts b/src/tree-sitter/types.ts index 17d353ae..1eb49d6d 100644 --- a/src/tree-sitter/types.ts +++ b/src/tree-sitter/types.ts @@ -2,7 +2,7 @@ import Parser from 'tree-sitter' export type ParameterTypeMeta = { name: string; regexp: string } -export const LanguageNames = ['java', 'typescript', 'c_sharp', 'php'] as const +export const LanguageNames = ['java', 'typescript', 'c_sharp', 'php', 'ruby'] as const export type LanguageName = typeof LanguageNames[number] export type Source = { diff --git a/test/tree-sitter/ExpressionBuilder.test.ts b/test/tree-sitter/ExpressionBuilder.test.ts index 10411d66..e9390eb1 100644 --- a/test/tree-sitter/ExpressionBuilder.test.ts +++ b/test/tree-sitter/ExpressionBuilder.test.ts @@ -9,7 +9,7 @@ import { ParserAdapter } from '../../src/tree-sitter/types.js' import { NodeParserAdapter } from '../../src/tree-sitter-node/NodeParserAdapter.js' import { WasmParserAdapter } from '../../src/tree-sitter-wasm/WasmParserAdapter.js' -const parameterTypeSupport: Set = new Set(['typescript', 'java']) +const parameterTypeSupport: Set = new Set(['typescript', 'java', 'ruby']) function defineContract(makeParserAdapter: () => ParserAdapter) { let expressionBuilder: ExpressionBuilder @@ -21,6 +21,9 @@ function defineContract(makeParserAdapter: () => ParserAdapter) { for (const dir of glob.sync(`test/tree-sitter/testdata/*`)) { const language = path.basename(dir) as LanguageName + // if (language !== 'ruby') { + // continue + // } it(`builds parameter types and expressions from ${language} source`, async () => { const contents = await Promise.all(glob.sync(`${dir}/**/*`).map((f) => readFile(f, 'utf-8'))) const sources = contents.map((content) => ({ diff --git a/test/tree-sitter/testdata/ruby/ParameterTypes.rb b/test/tree-sitter/testdata/ruby/ParameterTypes.rb new file mode 100644 index 00000000..1b911b5c --- /dev/null +++ b/test/tree-sitter/testdata/ruby/ParameterTypes.rb @@ -0,0 +1,13 @@ +require 'date' + +ParameterType( + name: 'uuid', + regexp: /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/, + transformer: ->(s) { s } +) + +ParameterType( + name: 'date', + regexp: /\d{4}-\d{2}-\d{2}/, + transformer: ->(s) { Date.parse(s) } +) diff --git a/test/tree-sitter/testdata/ruby/StepDefinitions.rb b/test/tree-sitter/testdata/ruby/StepDefinitions.rb new file mode 100644 index 00000000..2c3fa2cb --- /dev/null +++ b/test/tree-sitter/testdata/ruby/StepDefinitions.rb @@ -0,0 +1,8 @@ +Given('a {uuid}') do |uuid| +end + +When('a {date}') do |date| +end + +Then(/^a regexp$/) do +end From 109a792ddf166dee2dfca59d0d19a26686417f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aslak=20Helles=C3=B8y?= Date: Mon, 9 May 2022 16:57:01 +0100 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2954872f..36ee3d58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added +- Ruby support ([#44](https://github.com/cucumber/language-service/pull/44)) + ## [0.16.0] - 2022-05-05 ### Added - Build suggestions from unmatched gherkin steps ([#40](https://github.com/cucumber/language-service/pull/40))