lizard 1.17.31__py2.py3-none-any.whl → 1.18.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {lizard-1.17.31.dist-info → lizard-1.18.0.dist-info}/METADATA +5 -1
- {lizard-1.17.31.dist-info → lizard-1.18.0.dist-info}/RECORD +17 -17
- {lizard-1.17.31.dist-info → lizard-1.18.0.dist-info}/entry_points.txt +1 -0
- lizard.py +7 -7
- lizard_ext/checkstyleoutput.py +4 -2
- lizard_ext/version.py +1 -1
- lizard_languages/__init__.py +4 -2
- lizard_languages/clike.py +60 -1
- lizard_languages/python.py +36 -0
- lizard_languages/r.py +290 -0
- lizard_languages/rust.py +5 -0
- lizard_languages/st.py +139 -0
- lizard_languages/tsx.py +445 -11
- lizard_languages/typescript.py +214 -14
- lizard_languages/js_style_language_states.py +0 -185
- lizard_languages/jsx.py +0 -337
- {lizard-1.17.31.dist-info → lizard-1.18.0.dist-info}/LICENSE.txt +0 -0
- {lizard-1.17.31.dist-info → lizard-1.18.0.dist-info}/WHEEL +0 -0
- {lizard-1.17.31.dist-info → lizard-1.18.0.dist-info}/top_level.txt +0 -0
lizard_languages/typescript.py
CHANGED
|
@@ -5,7 +5,6 @@ Language parser for JavaScript
|
|
|
5
5
|
import re
|
|
6
6
|
from .code_reader import CodeReader, CodeStateMachine
|
|
7
7
|
from .clike import CCppCommentsMixin
|
|
8
|
-
from .js_style_language_states import JavaScriptStyleLanguageStates
|
|
9
8
|
from .js_style_regex_expression import js_style_regex_expression
|
|
10
9
|
|
|
11
10
|
|
|
@@ -64,17 +63,26 @@ class TypeScriptReader(CodeReader, CCppCommentsMixin):
|
|
|
64
63
|
def generate_tokens(source_code, addition='', token_class=None):
|
|
65
64
|
def split_template_literal(token, quote):
|
|
66
65
|
content = token[1:-1]
|
|
66
|
+
|
|
67
|
+
# Always yield opening quote
|
|
68
|
+
yield quote
|
|
69
|
+
|
|
70
|
+
# If no expressions, yield content as-is with quotes and closing quote
|
|
71
|
+
if '${' not in content:
|
|
72
|
+
if content:
|
|
73
|
+
yield quote + content + quote
|
|
74
|
+
yield quote
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
# Handle expressions
|
|
67
78
|
i = 0
|
|
68
|
-
# Special case for double-quoted strings starting with ${
|
|
69
|
-
if quote == '"' and content.startswith('${'):
|
|
70
|
-
yield '""'
|
|
71
79
|
while i < len(content):
|
|
72
80
|
idx = content.find('${', i)
|
|
73
81
|
if idx == -1:
|
|
74
82
|
if i < len(content):
|
|
75
83
|
yield quote + content[i:] + quote
|
|
76
84
|
break
|
|
77
|
-
if idx > i
|
|
85
|
+
if idx > i:
|
|
78
86
|
yield quote + content[i:idx] + quote
|
|
79
87
|
yield '${'
|
|
80
88
|
i = idx + 2
|
|
@@ -91,25 +99,35 @@ class TypeScriptReader(CodeReader, CCppCommentsMixin):
|
|
|
91
99
|
yield '}'
|
|
92
100
|
content = content[i:]
|
|
93
101
|
i = 0
|
|
102
|
+
|
|
103
|
+
# Always yield closing quote
|
|
104
|
+
yield quote
|
|
105
|
+
|
|
94
106
|
# Restore original addition pattern for template literals
|
|
95
107
|
addition = addition + r"|(?:\$\w+)" + r"|(?:\w+\?)" + r"|`.*?`"
|
|
96
108
|
for token in CodeReader.generate_tokens(source_code, addition, token_class):
|
|
97
109
|
if (
|
|
98
110
|
isinstance(token, str)
|
|
99
|
-
and
|
|
100
|
-
and token
|
|
101
|
-
and
|
|
111
|
+
and token.startswith('`')
|
|
112
|
+
and token.endswith('`')
|
|
113
|
+
and len(token) > 1
|
|
102
114
|
):
|
|
103
|
-
|
|
104
|
-
for t in split_template_literal(token, quote):
|
|
115
|
+
for t in split_template_literal(token, '`'):
|
|
105
116
|
yield t
|
|
106
117
|
continue
|
|
107
118
|
yield token
|
|
108
119
|
|
|
109
120
|
|
|
110
|
-
class TypeScriptStates(
|
|
121
|
+
class TypeScriptStates(CodeStateMachine):
|
|
111
122
|
def __init__(self, context):
|
|
112
123
|
super().__init__(context)
|
|
124
|
+
self.last_tokens = ''
|
|
125
|
+
self.function_name = ''
|
|
126
|
+
self.started_function = None
|
|
127
|
+
self.as_object = False
|
|
128
|
+
self._getter_setter_prefix = None
|
|
129
|
+
self.arrow_function_pending = False
|
|
130
|
+
self._ts_declare = False # Track if 'declare' was seen
|
|
113
131
|
|
|
114
132
|
def statemachine_before_return(self):
|
|
115
133
|
# Ensure the main function is closed at the end
|
|
@@ -117,17 +135,199 @@ class TypeScriptStates(JavaScriptStyleLanguageStates):
|
|
|
117
135
|
self._pop_function_from_stack()
|
|
118
136
|
|
|
119
137
|
def _state_global(self, token):
|
|
138
|
+
if token == 'declare':
|
|
139
|
+
self._ts_declare = True
|
|
140
|
+
return
|
|
141
|
+
if token == 'function' and getattr(self, '_ts_declare', False):
|
|
142
|
+
# Skip declared function
|
|
143
|
+
self._ts_declare = False
|
|
144
|
+
# Skip tokens until semicolon or newline
|
|
145
|
+
|
|
146
|
+
def skip_declared_function(t):
|
|
147
|
+
if t == ';' or self.context.newline:
|
|
148
|
+
self.next(self._state_global)
|
|
149
|
+
return True
|
|
150
|
+
return False
|
|
151
|
+
self.next(skip_declared_function)
|
|
152
|
+
return
|
|
153
|
+
self._ts_declare = False
|
|
154
|
+
|
|
155
|
+
if self.as_object:
|
|
156
|
+
# Support for getter/setter: look for 'get' or 'set' before method name
|
|
157
|
+
if token in ('get', 'set'):
|
|
158
|
+
self._getter_setter_prefix = token
|
|
159
|
+
return
|
|
160
|
+
if hasattr(self, '_getter_setter_prefix') and self._getter_setter_prefix:
|
|
161
|
+
# Next token is the property name
|
|
162
|
+
self.last_tokens = f"{self._getter_setter_prefix} {token}"
|
|
163
|
+
self._getter_setter_prefix = None
|
|
164
|
+
return
|
|
165
|
+
if token == '[':
|
|
166
|
+
self._collect_computed_name()
|
|
167
|
+
return
|
|
168
|
+
if token == ':':
|
|
169
|
+
self.function_name = self.last_tokens
|
|
170
|
+
return
|
|
171
|
+
elif token == '(':
|
|
172
|
+
if not self.started_function:
|
|
173
|
+
self.arrow_function_pending = True
|
|
174
|
+
self._function(self.last_tokens)
|
|
175
|
+
self.next(self._function, token)
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
if token in '.':
|
|
179
|
+
self._state = self._field
|
|
180
|
+
self.last_tokens += token
|
|
181
|
+
return
|
|
182
|
+
if token == 'function':
|
|
183
|
+
self._state = self._function
|
|
184
|
+
elif token in ('if', 'switch', 'for', 'while', 'catch'):
|
|
185
|
+
self.next(self._expecting_condition_and_statement_block)
|
|
186
|
+
elif token in ('else', 'do', 'try', 'final'):
|
|
187
|
+
self.next(self._expecting_statement_or_block)
|
|
188
|
+
elif token in ('=>',):
|
|
189
|
+
# Only handle arrow function body, do not push function here
|
|
190
|
+
self._state = self._arrow_function
|
|
191
|
+
elif token == '=':
|
|
192
|
+
self.function_name = self.last_tokens
|
|
193
|
+
elif token == "(":
|
|
194
|
+
self.sub_state(
|
|
195
|
+
self.__class__(self.context))
|
|
196
|
+
elif token in '{':
|
|
197
|
+
if self.started_function:
|
|
198
|
+
self.sub_state(
|
|
199
|
+
self.__class__(self.context),
|
|
200
|
+
self._pop_function_from_stack)
|
|
201
|
+
else:
|
|
202
|
+
self.read_object()
|
|
203
|
+
elif token in ('}', ')'):
|
|
204
|
+
self.statemachine_return()
|
|
205
|
+
elif self.context.newline or token == ';':
|
|
206
|
+
self.function_name = ''
|
|
207
|
+
self._pop_function_from_stack()
|
|
208
|
+
|
|
209
|
+
if token == '`':
|
|
210
|
+
self.next(self._state_template_literal)
|
|
120
211
|
if not self.as_object:
|
|
121
212
|
if token == ':':
|
|
122
213
|
self._consume_type_annotation()
|
|
123
214
|
return
|
|
124
|
-
|
|
215
|
+
self.last_tokens = token
|
|
216
|
+
|
|
217
|
+
def read_object(self):
|
|
218
|
+
def callback():
|
|
219
|
+
self.next(self._state_global)
|
|
220
|
+
|
|
221
|
+
object_reader = self.__class__(self.context)
|
|
222
|
+
object_reader.as_object = True
|
|
223
|
+
self.sub_state(object_reader, callback)
|
|
224
|
+
|
|
225
|
+
def _expecting_condition_and_statement_block(self, token):
|
|
226
|
+
def callback():
|
|
227
|
+
self.next(self._expecting_statement_or_block)
|
|
228
|
+
|
|
229
|
+
if token == "await":
|
|
230
|
+
return
|
|
231
|
+
|
|
232
|
+
if token != '(':
|
|
233
|
+
self.next(self._state_global, token)
|
|
234
|
+
return
|
|
235
|
+
|
|
236
|
+
self.sub_state(
|
|
237
|
+
self.__class__(self.context), callback)
|
|
238
|
+
|
|
239
|
+
def _expecting_statement_or_block(self, token):
|
|
240
|
+
def callback():
|
|
241
|
+
self.next(self._state_global)
|
|
242
|
+
if token == "{":
|
|
243
|
+
self.sub_state(
|
|
244
|
+
self.__class__(self.context), callback)
|
|
245
|
+
else:
|
|
246
|
+
self.next(self._state_global, token)
|
|
247
|
+
|
|
248
|
+
def _push_function_to_stack(self):
|
|
249
|
+
self.started_function = True
|
|
250
|
+
self.context.push_new_function(self.function_name or '(anonymous)')
|
|
251
|
+
|
|
252
|
+
def _pop_function_from_stack(self):
|
|
253
|
+
if self.started_function:
|
|
254
|
+
self.context.end_of_function()
|
|
255
|
+
self.started_function = None
|
|
256
|
+
|
|
257
|
+
def _arrow_function(self, token):
|
|
258
|
+
self._push_function_to_stack()
|
|
259
|
+
# Handle arrow function body
|
|
260
|
+
if token == '{':
|
|
261
|
+
# Block body
|
|
262
|
+
self.next(self._state_global, token)
|
|
263
|
+
else:
|
|
264
|
+
# Expression body
|
|
265
|
+
self.next(self._state_global, token)
|
|
266
|
+
|
|
267
|
+
def _function(self, token):
|
|
268
|
+
if token == '*':
|
|
269
|
+
return
|
|
270
|
+
if token != '(':
|
|
271
|
+
self.function_name = token
|
|
272
|
+
else:
|
|
273
|
+
if not self.started_function:
|
|
274
|
+
self._push_function_to_stack()
|
|
275
|
+
self.arrow_function_pending = False
|
|
276
|
+
self._state = self._dec
|
|
277
|
+
if token == '(':
|
|
278
|
+
self._dec(token)
|
|
279
|
+
|
|
280
|
+
def _field(self, token):
|
|
281
|
+
self.last_tokens += token
|
|
282
|
+
self._state = self._state_global
|
|
283
|
+
|
|
284
|
+
def _dec(self, token):
|
|
285
|
+
if token == ')':
|
|
286
|
+
self._state = self._expecting_func_opening_bracket
|
|
287
|
+
elif token != '(':
|
|
288
|
+
self.context.parameter(token)
|
|
289
|
+
return
|
|
290
|
+
self.context.add_to_long_function_name(" " + token)
|
|
125
291
|
|
|
126
292
|
def _expecting_func_opening_bracket(self, token):
|
|
293
|
+
# Do not reset started_function for arrow functions (=>)
|
|
127
294
|
if token == ':':
|
|
128
295
|
self._consume_type_annotation()
|
|
129
|
-
|
|
130
|
-
|
|
296
|
+
elif token != '{' and token != '=>':
|
|
297
|
+
self.started_function = None
|
|
298
|
+
self.next(self._state_global, token)
|
|
299
|
+
|
|
300
|
+
def _state_template_literal(self, token):
|
|
301
|
+
if token == '`':
|
|
302
|
+
self.next(self._state_global)
|
|
303
|
+
|
|
304
|
+
def _collect_computed_name(self):
|
|
305
|
+
# Collect tokens between [ and ]
|
|
306
|
+
tokens = []
|
|
307
|
+
|
|
308
|
+
def collect(token):
|
|
309
|
+
if token == ']':
|
|
310
|
+
# Try to join tokens and camelCase if possible
|
|
311
|
+
name = ''.join(tokens)
|
|
312
|
+
# Remove quotes and pluses for simple cases
|
|
313
|
+
name = name.replace("'", '').replace('"', '').replace('+', '').replace(' ', '')
|
|
314
|
+
# Lowercase first char, uppercase next word's first char
|
|
315
|
+
name = self._to_camel_case(name)
|
|
316
|
+
self.last_tokens = name
|
|
317
|
+
self.next(self._state_global)
|
|
318
|
+
return True
|
|
319
|
+
tokens.append(token)
|
|
320
|
+
return False
|
|
321
|
+
self.next(collect)
|
|
322
|
+
|
|
323
|
+
def _to_camel_case(self, s):
|
|
324
|
+
# Simple camelCase conversion for test case
|
|
325
|
+
if not s:
|
|
326
|
+
return s
|
|
327
|
+
parts = s.split()
|
|
328
|
+
if not parts:
|
|
329
|
+
return s
|
|
330
|
+
return parts[0][0].lower() + parts[0][1:] + ''.join(p.capitalize() for p in parts[1:])
|
|
131
331
|
|
|
132
332
|
def _consume_type_annotation(self):
|
|
133
333
|
typeStates = TypeScriptTypeAnnotationStates(self.context)
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
'''
|
|
2
|
-
"JavaScript style language" includes JavaScript and PHP
|
|
3
|
-
'''
|
|
4
|
-
|
|
5
|
-
from .code_reader import CodeStateMachine
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class JavaScriptStyleLanguageStates(CodeStateMachine): # pylint: disable=R0903
|
|
9
|
-
def __init__(self, context):
|
|
10
|
-
super(JavaScriptStyleLanguageStates, self).__init__(context)
|
|
11
|
-
self.last_tokens = ''
|
|
12
|
-
self.function_name = ''
|
|
13
|
-
self.started_function = None
|
|
14
|
-
self.as_object = False
|
|
15
|
-
self._getter_setter_prefix = None
|
|
16
|
-
self.arrow_function_pending = False
|
|
17
|
-
|
|
18
|
-
def _state_global(self, token):
|
|
19
|
-
if self.as_object:
|
|
20
|
-
# Support for getter/setter: look for 'get' or 'set' before method name
|
|
21
|
-
if token in ('get', 'set'):
|
|
22
|
-
self._getter_setter_prefix = token
|
|
23
|
-
return
|
|
24
|
-
if hasattr(self, '_getter_setter_prefix') and self._getter_setter_prefix:
|
|
25
|
-
# Next token is the property name
|
|
26
|
-
self.last_tokens = f"{self._getter_setter_prefix} {token}"
|
|
27
|
-
self._getter_setter_prefix = None
|
|
28
|
-
return
|
|
29
|
-
if token == '[':
|
|
30
|
-
self._collect_computed_name()
|
|
31
|
-
return
|
|
32
|
-
if token == ':':
|
|
33
|
-
self.function_name = self.last_tokens
|
|
34
|
-
return
|
|
35
|
-
elif token == '(':
|
|
36
|
-
if not self.started_function:
|
|
37
|
-
self.arrow_function_pending = True
|
|
38
|
-
self._function(self.last_tokens)
|
|
39
|
-
self.next(self._function, token)
|
|
40
|
-
return
|
|
41
|
-
|
|
42
|
-
if token in '.':
|
|
43
|
-
self._state = self._field
|
|
44
|
-
self.last_tokens += token
|
|
45
|
-
return
|
|
46
|
-
if token == 'function':
|
|
47
|
-
self._state = self._function
|
|
48
|
-
elif token in ('if', 'switch', 'for', 'while', 'catch'):
|
|
49
|
-
self.next(self._expecting_condition_and_statement_block)
|
|
50
|
-
elif token in ('else', 'do', 'try', 'final'):
|
|
51
|
-
self.next(self._expecting_statement_or_block)
|
|
52
|
-
elif token in ('=>',):
|
|
53
|
-
# Only handle arrow function body, do not push function here
|
|
54
|
-
self._state = self._arrow_function
|
|
55
|
-
elif token == '=':
|
|
56
|
-
self.function_name = self.last_tokens
|
|
57
|
-
elif token == "(":
|
|
58
|
-
self.sub_state(
|
|
59
|
-
self.__class__(self.context))
|
|
60
|
-
elif token in '{':
|
|
61
|
-
if self.started_function:
|
|
62
|
-
self.sub_state(
|
|
63
|
-
self.__class__(self.context),
|
|
64
|
-
self._pop_function_from_stack)
|
|
65
|
-
else:
|
|
66
|
-
self.read_object()
|
|
67
|
-
elif token in ('}', ')'):
|
|
68
|
-
self.statemachine_return()
|
|
69
|
-
elif self.context.newline or token == ';':
|
|
70
|
-
self.function_name = ''
|
|
71
|
-
self._pop_function_from_stack()
|
|
72
|
-
|
|
73
|
-
self.last_tokens = token
|
|
74
|
-
|
|
75
|
-
def read_object(self):
|
|
76
|
-
def callback():
|
|
77
|
-
self.next(self._state_global)
|
|
78
|
-
|
|
79
|
-
object_reader = self.__class__(self.context)
|
|
80
|
-
object_reader.as_object = True
|
|
81
|
-
self.sub_state(object_reader, callback)
|
|
82
|
-
|
|
83
|
-
def statemachine_before_return(self):
|
|
84
|
-
self._pop_function_from_stack()
|
|
85
|
-
|
|
86
|
-
def _expecting_condition_and_statement_block(self, token):
|
|
87
|
-
def callback():
|
|
88
|
-
self.next(self._expecting_statement_or_block)
|
|
89
|
-
|
|
90
|
-
if token == "await":
|
|
91
|
-
return
|
|
92
|
-
|
|
93
|
-
if token != '(':
|
|
94
|
-
self.next(self._state_global, token)
|
|
95
|
-
return
|
|
96
|
-
|
|
97
|
-
self.sub_state(
|
|
98
|
-
self.__class__(self.context), callback)
|
|
99
|
-
|
|
100
|
-
def _expecting_statement_or_block(self, token):
|
|
101
|
-
def callback():
|
|
102
|
-
self.next(self._state_global)
|
|
103
|
-
if token == "{":
|
|
104
|
-
self.sub_state(
|
|
105
|
-
self.__class__(self.context), callback)
|
|
106
|
-
else:
|
|
107
|
-
self.next(self._state_global, token)
|
|
108
|
-
|
|
109
|
-
def _push_function_to_stack(self):
|
|
110
|
-
self.started_function = True
|
|
111
|
-
self.context.push_new_function(self.function_name or '(anonymous)')
|
|
112
|
-
|
|
113
|
-
def _pop_function_from_stack(self):
|
|
114
|
-
if self.started_function:
|
|
115
|
-
self.context.end_of_function()
|
|
116
|
-
self.started_function = None
|
|
117
|
-
|
|
118
|
-
def _arrow_function(self, token):
|
|
119
|
-
self._push_function_to_stack()
|
|
120
|
-
# Handle arrow function body
|
|
121
|
-
if token == '{':
|
|
122
|
-
# Block body
|
|
123
|
-
self.next(self._state_global, token)
|
|
124
|
-
else:
|
|
125
|
-
# Expression body
|
|
126
|
-
self.next(self._state_global, token)
|
|
127
|
-
|
|
128
|
-
def _function(self, token):
|
|
129
|
-
if token == '*':
|
|
130
|
-
return
|
|
131
|
-
if token != '(':
|
|
132
|
-
self.function_name = token
|
|
133
|
-
else:
|
|
134
|
-
if not self.started_function:
|
|
135
|
-
self._push_function_to_stack()
|
|
136
|
-
self.arrow_function_pending = False
|
|
137
|
-
self._state = self._dec
|
|
138
|
-
if token == '(':
|
|
139
|
-
self._dec(token)
|
|
140
|
-
|
|
141
|
-
def _field(self, token):
|
|
142
|
-
self.last_tokens += token
|
|
143
|
-
self._state = self._state_global
|
|
144
|
-
|
|
145
|
-
def _dec(self, token):
|
|
146
|
-
if token == ')':
|
|
147
|
-
self._state = self._expecting_func_opening_bracket
|
|
148
|
-
elif token != '(':
|
|
149
|
-
self.context.parameter(token)
|
|
150
|
-
return
|
|
151
|
-
self.context.add_to_long_function_name(" " + token)
|
|
152
|
-
|
|
153
|
-
def _expecting_func_opening_bracket(self, token):
|
|
154
|
-
# Do not reset started_function for arrow functions (=>)
|
|
155
|
-
if token != '{' and token != '=>':
|
|
156
|
-
self.started_function = None
|
|
157
|
-
self.next(self._state_global, token)
|
|
158
|
-
|
|
159
|
-
def _collect_computed_name(self):
|
|
160
|
-
# Collect tokens between [ and ]
|
|
161
|
-
tokens = []
|
|
162
|
-
|
|
163
|
-
def collect(token):
|
|
164
|
-
if token == ']':
|
|
165
|
-
# Try to join tokens and camelCase if possible
|
|
166
|
-
name = ''.join(tokens)
|
|
167
|
-
# Remove quotes and pluses for simple cases
|
|
168
|
-
name = name.replace("'", '').replace('"', '').replace('+', '').replace(' ', '')
|
|
169
|
-
# Lowercase first char, uppercase next word's first char
|
|
170
|
-
name = self._to_camel_case(name)
|
|
171
|
-
self.last_tokens = name
|
|
172
|
-
self.next(self._state_global)
|
|
173
|
-
return True
|
|
174
|
-
tokens.append(token)
|
|
175
|
-
return False
|
|
176
|
-
self.next(collect)
|
|
177
|
-
|
|
178
|
-
def _to_camel_case(self, s):
|
|
179
|
-
# Simple camelCase conversion for test case
|
|
180
|
-
if not s:
|
|
181
|
-
return s
|
|
182
|
-
parts = s.split()
|
|
183
|
-
if not parts:
|
|
184
|
-
return s
|
|
185
|
-
return parts[0][0].lower() + parts[0][1:] + ''.join(p.capitalize() for p in parts[1:])
|