-
-
Notifications
You must be signed in to change notification settings - Fork 22
/
pythonLanguage.ts
142 lines (136 loc) · 4.37 KB
/
pythonLanguage.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import { StringOrRegExp } from '@cucumber/cucumber-expressions'
import { Language, TreeSitterSyntaxNode } from './types.js'
export const pythonLanguage: Language = {
toParameterTypeName(node: TreeSitterSyntaxNode) {
switch (node.type) {
case 'string': {
return stringLiteral(node.text)
}
case 'concatenated_string': {
return concatStringLiteral(node.text)
}
case 'identifier': {
return node.text
}
default: {
throw new Error(`Unsupported node type ${node.type}`)
}
}
},
toParameterTypeRegExps(node: TreeSitterSyntaxNode) {
switch (node.type) {
case 'string': {
return RegExp(cleanRegExp(stringLiteral(node.text)))
}
case 'concatenated_string': {
return RegExp(cleanRegExp(concatStringLiteral(node.text)))
}
case 'identifier': {
return RegExp(cleanRegExp(stringLiteral(node.text)))
}
default: {
throw new Error(`Unsupported node type ${node.type}`)
}
}
},
toStepDefinitionExpression(node: TreeSitterSyntaxNode): StringOrRegExp {
// This removes the head and tail apostrophes.
// TODO: This should be temporary. Python supports
// a wider array of regex features than javascript
// a singular way of communicating regex consistent
// across languages is necessary
return toStringOrRegExp(node.text)
},
defineParameterTypeQueries: [
`(call
arguments: (argument_list
(keyword_argument
name: (identifier) @name-key
value: (string) @name
(#eq? @name-key "name")
)?
(keyword_argument
name: (identifier) @regexp-key
value: (string) @expression
(#eq? @regexp-key "regexp")
)?
(keyword_argument
name: (identifier) @regexp-key
value: (concatenated_string) @expression
(#eq? @regexp-key "regexp")
)?
))@root`,
],
defineStepDefinitionQueries: [
`
(decorated_definition
(decorator
(call
function: (identifier) @method
arguments: (argument_list (string) @expression)
)
)
(#match? @method "(given|when|then)")
) @root
`,
],
snippetParameters: {
int: { type: 'int' },
float: { type: 'float' },
word: { type: 'str' },
string: { type: 'str' },
double: { type: 'double' },
bigdecimal: { type: 'decimal' },
byte: { type: 'byte' },
short: { type: 'short' },
long: { type: 'long' },
biginteger: { type: 'int' },
'': { type: 'Object', name: 'arg' },
},
defaultSnippetTemplate: `
@{{ #lowercase }}{{ keyword }}{{ /lowercase }}('{{ expression }}')
def step_{{ #lowercase }}{{ keyword }}{{ /lowercase }}(context{{ #parameters }}, {{ name }}{{ /parameters }}):
# This was autogenerated using cucumber syntax.
# Please convert to use regular expressions, as Behave does not currently support Cucumber Expressions.`,
}
function cleanRegExp(regExpString: string): string {
const startsWith = regExpString[0]
switch (startsWith) {
case '/':
return regExpString.slice(1, -1)
default:
return regExpString
}
}
export function toStringOrRegExp(step: string): StringOrRegExp {
// Remove explicit 'u' unicode prefix
const isUString = step.startsWith('u')
const stepText = isUString ? step.slice(1) : step
const strippedStepText = stepText.slice(1, -1)
return isRegExp(strippedStepText)
? RegExp(cleanRegExp(strippedStepText.split('?P').join('')))
: strippedStepText
}
export function concatStringLiteral(text: string): string {
const isFString = text.startsWith('f')
const cleanWord = isFString ? text.slice(1) : text
const postSplitCleanWord = cleanWord
.split('\\\n')
.map((x) => x.replace(/"/g, ''))
.map((x) => x.trim())
.join('')
return postSplitCleanWord
}
export function stringLiteral(text: string): string {
const isFString = text.startsWith('f')
const cleanWord = isFString ? text.slice(1).slice(1, -1) : text.slice(1, -1)
return cleanWord
}
export function isRegExp(cleanWord: string): boolean {
const startsWithSlash = cleanWord.startsWith('/')
const namedGroupMatch = /\?P/
const specialCharsMatch = /\(|\)|\.|\*|\\|\|/
const containsNamedGroups = namedGroupMatch.test(cleanWord)
const containsSpecialChars = specialCharsMatch.test(cleanWord)
return startsWithSlash || containsNamedGroups || containsSpecialChars
}