lizard 1.17.31__py2.py3-none-any.whl → 1.19.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.
@@ -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 and not (quote == '"' and idx == 0 and content.startswith('${')):
85
+ if idx > i:
78
86
  yield quote + content[i:idx] + quote
79
87
  yield '${'
80
88
  i = idx + 2
@@ -91,25 +99,38 @@ 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 (token.startswith('`') or token.startswith('"'))
100
- and token[0] == token[-1]
101
- and '${' in token
111
+ and token.startswith('`')
112
+ and token.endswith('`')
113
+ and len(token) > 1
102
114
  ):
103
- quote = token[0]
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(JavaScriptStyleLanguageStates):
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
131
+ self._static_seen = False # Track if 'static' was seen
132
+ self._async_seen = False # Track if 'async' was seen
133
+ self._prev_token = '' # Track previous token to detect method calls
113
134
 
114
135
  def statemachine_before_return(self):
115
136
  # Ensure the main function is closed at the end
@@ -117,17 +138,246 @@ class TypeScriptStates(JavaScriptStyleLanguageStates):
117
138
  self._pop_function_from_stack()
118
139
 
119
140
  def _state_global(self, token):
141
+ if token == 'declare':
142
+ self._ts_declare = True
143
+ return
144
+ if token == 'function' and getattr(self, '_ts_declare', False):
145
+ # Skip declared function
146
+ self._ts_declare = False
147
+ # Skip tokens until semicolon or newline
148
+
149
+ def skip_declared_function(t):
150
+ if t == ';' or self.context.newline:
151
+ self.next(self._state_global)
152
+ return True
153
+ return False
154
+ self.next(skip_declared_function)
155
+ return
156
+ self._ts_declare = False
157
+
158
+ # Track static and async modifiers
159
+ if token == 'static':
160
+ self._static_seen = True
161
+ self._prev_token = token
162
+ return
163
+ if token == 'async':
164
+ self._async_seen = True
165
+ self._prev_token = token
166
+ return
167
+ if token == 'new':
168
+ # Track 'new' keyword to avoid treating constructors as functions
169
+ self._prev_token = token
170
+ return
171
+
172
+ if self.as_object:
173
+ # Support for getter/setter: look for 'get' or 'set' before method name
174
+ if token in ('get', 'set'):
175
+ self._getter_setter_prefix = token
176
+ return
177
+ if hasattr(self, '_getter_setter_prefix') and self._getter_setter_prefix:
178
+ # Next token is the property name
179
+ self.last_tokens = f"{self._getter_setter_prefix} {token}"
180
+ self._getter_setter_prefix = None
181
+ return
182
+ if token == '[':
183
+ self._collect_computed_name()
184
+ return
185
+ if token == ':':
186
+ self.function_name = self.last_tokens
187
+ return
188
+ elif token == '(':
189
+ # Check if this is a method call (previous token was . or this/identifier)
190
+ if self._prev_token == '.' or self._prev_token == 'new':
191
+ # This is a method call, not a function definition
192
+ self._prev_token = token
193
+ return
194
+ if not self.started_function:
195
+ self.arrow_function_pending = True
196
+ self._function(self.last_tokens)
197
+ self.next(self._function, token)
198
+ return
199
+ # If we've seen async/static and this is an identifier, it's likely a method name
200
+ elif (self._async_seen or self._static_seen) and token not in ('*', 'function'):
201
+ # This is a method name after async/static
202
+ self.last_tokens = token
203
+ return
204
+
205
+ if token in '.':
206
+ self._state = self._field
207
+ self.last_tokens += token
208
+ self._prev_token = token
209
+ return
210
+ if token == 'function':
211
+ self._state = self._function
212
+ elif token in ('if', 'switch', 'for', 'while', 'catch'):
213
+ self.next(self._expecting_condition_and_statement_block)
214
+ elif token in ('else', 'do', 'try', 'final'):
215
+ self.next(self._expecting_statement_or_block)
216
+ elif token in ('=>',):
217
+ # Only handle arrow function body, do not push function here
218
+ self._state = self._arrow_function
219
+ elif token == '=':
220
+ self.function_name = self.last_tokens
221
+ elif token == "(":
222
+ # Check if this is a method call or constructor
223
+ if self._prev_token == '.' or self._prev_token == 'new':
224
+ # This is a method call or constructor, not a function definition
225
+ self.sub_state(
226
+ self.__class__(self.context))
227
+ else:
228
+ self.sub_state(
229
+ self.__class__(self.context))
230
+ elif token in '{':
231
+ if self.started_function:
232
+ self.sub_state(
233
+ self.__class__(self.context),
234
+ self._pop_function_from_stack)
235
+ else:
236
+ self.read_object()
237
+ elif token in ('}', ')'):
238
+ self.statemachine_return()
239
+ elif self.context.newline or token == ';':
240
+ self.function_name = ''
241
+ self._pop_function_from_stack()
242
+ # Reset modifiers on newline/semicolon
243
+ self._static_seen = False
244
+ self._async_seen = False
245
+
246
+ if token == '`':
247
+ self.next(self._state_template_literal)
120
248
  if not self.as_object:
121
249
  if token == ':':
122
250
  self._consume_type_annotation()
251
+ self._prev_token = token
123
252
  return
124
- super()._state_global(token)
253
+ self.last_tokens = token
254
+ # Don't overwrite _prev_token if it's 'new' or '.' (preserve for next token)
255
+ if self._prev_token not in ('new', '.'):
256
+ self._prev_token = token
257
+
258
+ def read_object(self):
259
+ def callback():
260
+ self.next(self._state_global)
261
+
262
+ object_reader = self.__class__(self.context)
263
+ object_reader.as_object = True
264
+ # Pass along the modifier flags
265
+ object_reader._static_seen = self._static_seen
266
+ object_reader._async_seen = self._async_seen
267
+ self.sub_state(object_reader, callback)
268
+ # Reset modifiers after entering object
269
+ self._static_seen = False
270
+ self._async_seen = False
271
+
272
+ def _expecting_condition_and_statement_block(self, token):
273
+ def callback():
274
+ self.next(self._expecting_statement_or_block)
275
+
276
+ if token == "await":
277
+ return
278
+
279
+ if token != '(':
280
+ self.next(self._state_global, token)
281
+ return
282
+
283
+ self.sub_state(
284
+ self.__class__(self.context), callback)
285
+
286
+ def _expecting_statement_or_block(self, token):
287
+ def callback():
288
+ self.next(self._state_global)
289
+ if token == "{":
290
+ self.sub_state(
291
+ self.__class__(self.context), callback)
292
+ else:
293
+ self.next(self._state_global, token)
294
+
295
+ def _push_function_to_stack(self):
296
+ self.started_function = True
297
+ self.context.push_new_function(self.function_name or '(anonymous)')
298
+
299
+ def _pop_function_from_stack(self):
300
+ if self.started_function:
301
+ self.context.end_of_function()
302
+ self.started_function = None
303
+
304
+ def _arrow_function(self, token):
305
+ self._push_function_to_stack()
306
+ # Handle arrow function body
307
+ if token == '{':
308
+ # Block body
309
+ self.next(self._state_global, token)
310
+ else:
311
+ # Expression body
312
+ self.next(self._state_global, token)
313
+
314
+ def _function(self, token):
315
+ if token == '*':
316
+ return
317
+ if token != '(':
318
+ self.function_name = token
319
+ # Reset modifiers after setting function name
320
+ self._static_seen = False
321
+ self._async_seen = False
322
+ else:
323
+ if not self.started_function:
324
+ self._push_function_to_stack()
325
+ self.arrow_function_pending = False
326
+ self._state = self._dec
327
+ if token == '(':
328
+ self._dec(token)
329
+
330
+ def _field(self, token):
331
+ self.last_tokens += token
332
+ self._state = self._state_global
333
+
334
+ def _dec(self, token):
335
+ if token == ')':
336
+ self._state = self._expecting_func_opening_bracket
337
+ elif token != '(':
338
+ self.context.parameter(token)
339
+ return
340
+ self.context.add_to_long_function_name(" " + token)
125
341
 
126
342
  def _expecting_func_opening_bracket(self, token):
343
+ # Do not reset started_function for arrow functions (=>)
127
344
  if token == ':':
128
345
  self._consume_type_annotation()
129
- else:
130
- super()._expecting_func_opening_bracket(token)
346
+ elif token != '{' and token != '=>':
347
+ self.started_function = None
348
+ self.next(self._state_global, token)
349
+
350
+ def _state_template_literal(self, token):
351
+ if token == '`':
352
+ self.next(self._state_global)
353
+
354
+ def _collect_computed_name(self):
355
+ # Collect tokens between [ and ]
356
+ tokens = []
357
+
358
+ def collect(token):
359
+ if token == ']':
360
+ # Try to join tokens and camelCase if possible
361
+ name = ''.join(tokens)
362
+ # Remove quotes and pluses for simple cases
363
+ name = name.replace("'", '').replace('"', '').replace('+', '').replace(' ', '')
364
+ # Lowercase first char, uppercase next word's first char
365
+ name = self._to_camel_case(name)
366
+ self.last_tokens = name
367
+ self.next(self._state_global)
368
+ return True
369
+ tokens.append(token)
370
+ return False
371
+ self.next(collect)
372
+
373
+ def _to_camel_case(self, s):
374
+ # Simple camelCase conversion for test case
375
+ if not s:
376
+ return s
377
+ parts = s.split()
378
+ if not parts:
379
+ return s
380
+ return parts[0][0].lower() + parts[0][1:] + ''.join(p.capitalize() for p in parts[1:])
131
381
 
132
382
  def _consume_type_annotation(self):
133
383
  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:])