pulse-framework 0.1.73__py3-none-any.whl → 0.1.75__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.
@@ -10,8 +10,9 @@ from __future__ import annotations
10
10
  import ast
11
11
  import re
12
12
  from collections.abc import Callable, Mapping
13
+ from dataclasses import dataclass
13
14
  from pathlib import Path
14
- from typing import Any, cast
15
+ from typing import Any, cast, override
15
16
 
16
17
  from pulse.transpiler.builtins import BUILTINS, emit_method
17
18
  from pulse.transpiler.errors import TranspileError
@@ -30,6 +31,7 @@ from pulse.transpiler.nodes import (
30
31
  Function,
31
32
  Identifier,
32
33
  If,
34
+ LetDecl,
33
35
  Literal,
34
36
  Member,
35
37
  New,
@@ -78,6 +80,228 @@ ALLOWED_CMPOPS: dict[type[ast.cmpop], str] = {
78
80
  }
79
81
 
80
82
 
83
+ def _collect_param_names(args: ast.arguments) -> list[str]:
84
+ """Collect argument names (regular, vararg, kwonly, kwarg)."""
85
+ names: list[str] = [arg.arg for arg in args.args]
86
+ if args.vararg:
87
+ names.append(args.vararg.arg)
88
+ names.extend(arg.arg for arg in args.kwonlyargs)
89
+ if args.kwarg:
90
+ names.append(args.kwarg.arg)
91
+ return names
92
+
93
+
94
+ @dataclass(slots=True)
95
+ class Scope:
96
+ locals: set[str]
97
+ params: set[str]
98
+ parent: "Scope | None" = None
99
+
100
+
101
+ class ScopeAnalyzer(ast.NodeVisitor):
102
+ """Collect locals per scope (function/lambda/comprehension)."""
103
+
104
+ _scopes: dict[ast.AST, Scope]
105
+ _stack: list[Scope]
106
+ _global_scope: Scope
107
+
108
+ def __init__(self) -> None:
109
+ self._scopes = {}
110
+ self._stack = []
111
+ self._global_scope = Scope(locals=set(), params=set(), parent=None)
112
+
113
+ def analyze(
114
+ self, node: ast.FunctionDef | ast.AsyncFunctionDef
115
+ ) -> dict[ast.AST, Scope]:
116
+ self._stack.append(self._global_scope)
117
+ self._visit_defaults(node.args)
118
+ scope = self._new_scope(
119
+ node, _collect_param_names(node.args), parent=self._global_scope
120
+ )
121
+ self._stack.append(scope)
122
+ for stmt in node.body:
123
+ self.visit(stmt)
124
+ self._stack.pop()
125
+ self._stack.pop()
126
+ return self._scopes
127
+
128
+ def _new_scope(
129
+ self,
130
+ node: ast.AST,
131
+ params: list[str],
132
+ *,
133
+ parent: Scope | None,
134
+ ) -> Scope:
135
+ param_set = set(params)
136
+ scope = Scope(locals=set(param_set), params=param_set, parent=parent)
137
+ self._scopes[node] = scope
138
+ return scope
139
+
140
+ def _current_scope(self) -> Scope:
141
+ return self._stack[-1]
142
+
143
+ def _add_local(self, name: str) -> None:
144
+ self._current_scope().locals.add(name)
145
+
146
+ def _add_targets(self, target: ast.expr) -> None:
147
+ if isinstance(target, ast.Name):
148
+ self._add_local(target.id)
149
+ return
150
+ if isinstance(target, (ast.Tuple, ast.List)):
151
+ for elt in target.elts:
152
+ if isinstance(elt, ast.Name):
153
+ self._add_local(elt.id)
154
+
155
+ def _visit_target_expr(self, target: ast.expr) -> None:
156
+ if isinstance(target, (ast.Tuple, ast.List)):
157
+ for elt in target.elts:
158
+ self._visit_target_expr(elt)
159
+ return
160
+ self.visit(target)
161
+
162
+ def _analyze_function(self, node: ast.FunctionDef | ast.AsyncFunctionDef) -> None:
163
+ self._visit_defaults(node.args)
164
+ scope = self._new_scope(
165
+ node,
166
+ _collect_param_names(node.args),
167
+ parent=self._current_scope(),
168
+ )
169
+ self._stack.append(scope)
170
+ for stmt in node.body:
171
+ self.visit(stmt)
172
+ self._stack.pop()
173
+
174
+ @property
175
+ def global_scope(self) -> Scope:
176
+ return self._global_scope
177
+
178
+ def _visit_defaults(self, args: ast.arguments) -> None:
179
+ for default in args.defaults:
180
+ self.visit(default)
181
+ for default in args.kw_defaults:
182
+ if default is not None:
183
+ self.visit(default)
184
+
185
+ @override
186
+ def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
187
+ self._add_local(node.name)
188
+ self._analyze_function(node)
189
+
190
+ @override
191
+ def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> None:
192
+ self._add_local(node.name)
193
+ self._analyze_function(node)
194
+
195
+ @override
196
+ def visit_Lambda(self, node: ast.Lambda) -> None:
197
+ scope = self._new_scope(
198
+ node,
199
+ _collect_param_names(node.args),
200
+ parent=self._current_scope(),
201
+ )
202
+ self._stack.append(scope)
203
+ self.visit(node.body)
204
+ self._stack.pop()
205
+
206
+ def _visit_comprehension(
207
+ self,
208
+ node: ast.ListComp | ast.SetComp | ast.DictComp | ast.GeneratorExp,
209
+ *,
210
+ elt: ast.expr,
211
+ key: ast.expr | None = None,
212
+ ) -> None:
213
+ scope = self._new_scope(node, [], parent=self._current_scope())
214
+ self._stack.append(scope)
215
+ if key is not None:
216
+ self.visit(key)
217
+ self.visit(elt)
218
+ for gen in node.generators:
219
+ self.visit(gen.iter)
220
+ for if_node in gen.ifs:
221
+ self.visit(if_node)
222
+ self._stack.pop()
223
+
224
+ @override
225
+ def visit_ListComp(self, node: ast.ListComp) -> None:
226
+ self._visit_comprehension(node, elt=node.elt)
227
+
228
+ @override
229
+ def visit_SetComp(self, node: ast.SetComp) -> None:
230
+ self._visit_comprehension(node, elt=node.elt)
231
+
232
+ @override
233
+ def visit_GeneratorExp(self, node: ast.GeneratorExp) -> None:
234
+ self._visit_comprehension(node, elt=node.elt)
235
+
236
+ @override
237
+ def visit_DictComp(self, node: ast.DictComp) -> None:
238
+ self._visit_comprehension(node, elt=node.value, key=node.key)
239
+
240
+ @override
241
+ def visit_Assign(self, node: ast.Assign) -> None:
242
+ for target in node.targets:
243
+ if isinstance(target, (ast.Name, ast.Tuple, ast.List)):
244
+ self._add_targets(target)
245
+ self._visit_target_expr(target)
246
+ self.visit(node.value)
247
+
248
+ @override
249
+ def visit_AnnAssign(self, node: ast.AnnAssign) -> None:
250
+ if isinstance(node.target, (ast.Name, ast.Tuple, ast.List)):
251
+ self._add_targets(node.target)
252
+ self._visit_target_expr(node.target)
253
+ if node.value is not None:
254
+ self.visit(node.value)
255
+
256
+ @override
257
+ def visit_AugAssign(self, node: ast.AugAssign) -> None:
258
+ if isinstance(node.target, (ast.Name, ast.Tuple, ast.List)):
259
+ self._add_targets(node.target)
260
+ self._visit_target_expr(node.target)
261
+ self.visit(node.value)
262
+
263
+ @override
264
+ def visit_For(self, node: ast.For) -> None:
265
+ if isinstance(node.target, (ast.Name, ast.Tuple, ast.List)):
266
+ self._add_targets(node.target)
267
+ self._visit_target_expr(node.target)
268
+ self.visit(node.iter)
269
+ for stmt in node.body:
270
+ self.visit(stmt)
271
+ for stmt in node.orelse:
272
+ self.visit(stmt)
273
+
274
+ @override
275
+ def visit_ExceptHandler(self, node: ast.ExceptHandler) -> None:
276
+ if node.name:
277
+ self._add_local(node.name)
278
+ if node.type is not None:
279
+ self.visit(node.type)
280
+ for stmt in node.body:
281
+ self.visit(stmt)
282
+
283
+ @override
284
+ def visit_With(self, node: ast.With) -> None:
285
+ for item in node.items:
286
+ if item.optional_vars and isinstance(
287
+ item.optional_vars, (ast.Name, ast.Tuple, ast.List)
288
+ ):
289
+ self._add_targets(item.optional_vars)
290
+ if item.optional_vars is not None:
291
+ self._visit_target_expr(item.optional_vars)
292
+ self.visit(item.context_expr)
293
+ for stmt in node.body:
294
+ self.visit(stmt)
295
+
296
+ @override
297
+ def visit_Global(self, node: ast.Global) -> None:
298
+ raise TranspileError("global is not supported", node=node)
299
+
300
+ @override
301
+ def visit_Nonlocal(self, node: ast.Nonlocal) -> None:
302
+ raise TranspileError("nonlocal is not supported", node=node)
303
+
304
+
81
305
  class Transpiler:
82
306
  """Transpile Python AST to v2 Expr/Stmt AST nodes.
83
307
 
@@ -93,10 +317,12 @@ class Transpiler:
93
317
  fndef: ast.FunctionDef | ast.AsyncFunctionDef
94
318
  args: list[str]
95
319
  deps: Mapping[str, Expr]
96
- locals: set[str]
97
320
  jsx: bool
98
321
  source_file: Path | None
99
322
  _temp_counter: int
323
+ _scope_map: dict[ast.AST, Scope]
324
+ _scope_stack: list[Scope]
325
+ _global_scope: Scope
100
326
 
101
327
  def __init__(
102
328
  self,
@@ -109,22 +335,21 @@ class Transpiler:
109
335
  self.fndef = fndef
110
336
  self.source_file = source_file
111
337
  # Collect all argument names (regular, vararg, kwonly, kwarg)
112
- args: list[str] = [arg.arg for arg in fndef.args.args]
113
- if fndef.args.vararg:
114
- args.append(fndef.args.vararg.arg)
115
- args.extend(arg.arg for arg in fndef.args.kwonlyargs)
116
- if fndef.args.kwarg:
117
- args.append(fndef.args.kwarg.arg)
118
- self.args = args
338
+ self.args = _collect_param_names(fndef.args)
119
339
  self.deps = deps
120
340
  self.jsx = jsx
121
- self.locals = set(self.args)
122
341
  self._temp_counter = 0
342
+ analyzer = ScopeAnalyzer()
343
+ self._scope_map = analyzer.analyze(fndef)
344
+ self._global_scope = analyzer.global_scope
345
+ self._scope_stack = [self._scope_map[fndef]]
123
346
  self.init_temp_counter()
124
347
 
125
348
  def init_temp_counter(self) -> None:
126
349
  """Initialize temp counter to avoid collisions with args or globals."""
127
- all_names = set(self.args) | set(self.deps.keys())
350
+ all_names = set(self.deps.keys())
351
+ for scope in self._scope_map.values():
352
+ all_names.update(scope.locals)
128
353
  counter = 0
129
354
  while f"$tmp{counter}" in all_names:
130
355
  counter += 1
@@ -136,6 +361,38 @@ class Transpiler:
136
361
  self._temp_counter += 1
137
362
  return name
138
363
 
364
+ def _current_scope(self) -> Scope:
365
+ return self._scope_stack[-1]
366
+
367
+ def _push_scope(self, node: ast.AST) -> None:
368
+ self._scope_stack.append(self._scope_map[node])
369
+
370
+ def _pop_scope(self) -> None:
371
+ self._scope_stack.pop()
372
+
373
+ def _is_local_here(self, name: str) -> bool:
374
+ return name in self._current_scope().locals
375
+
376
+ def _is_local(self, name: str) -> bool:
377
+ scope: Scope | None = self._current_scope()
378
+ while scope is not None:
379
+ if name in scope.locals:
380
+ return True
381
+ scope = scope.parent
382
+ return False
383
+
384
+ def _require_local(
385
+ self, name: str, *, node: ast.expr | ast.stmt | ast.excepthandler
386
+ ) -> None:
387
+ if not self._is_local_here(name):
388
+ raise TranspileError(f"Assignment to unknown local: {name}", node=node)
389
+
390
+ def _function_prelude(self, scope: Scope) -> list[Stmt]:
391
+ names = sorted(scope.locals - scope.params)
392
+ if not names:
393
+ return []
394
+ return [LetDecl(names)]
395
+
139
396
  # --- Entrypoint ---------------------------------------------------------
140
397
 
141
398
  def transpile(self) -> Function | Arrow:
@@ -176,7 +433,8 @@ class Transpiler:
176
433
  return Arrow(self.args, expr)
177
434
 
178
435
  # General case: Function (for JSX or multi-statement)
179
- stmts = [self.emit_stmt(s) for s in body]
436
+ prelude = self._function_prelude(self._current_scope())
437
+ stmts = prelude + [self.emit_stmt(s) for s in body]
180
438
  is_async = isinstance(self.fndef, ast.AsyncFunctionDef)
181
439
  args = [self._jsx_args()] if self.jsx else self.args
182
440
  return Function(args, stmts, is_async=is_async)
@@ -202,7 +460,7 @@ class Transpiler:
202
460
  if default_idx >= 0:
203
461
  # Has a default value
204
462
  default_node = args.defaults[default_idx]
205
- default_expr = self.emit_expr(default_node)
463
+ default_expr = self._emit_default_expr(default_node)
206
464
  default_out.clear()
207
465
  default_expr.emit(default_out)
208
466
  destructure_parts.append(f"{param_name} = {''.join(default_out)}")
@@ -220,7 +478,7 @@ class Transpiler:
220
478
  default_node = args.kw_defaults[i]
221
479
  if default_node is not None:
222
480
  # Has a default value
223
- default_expr = self.emit_expr(default_node)
481
+ default_expr = self._emit_default_expr(default_node)
224
482
  default_out.clear()
225
483
  default_expr.emit(default_out)
226
484
  destructure_parts.append(f"{param_name} = {''.join(default_out)}")
@@ -234,6 +492,14 @@ class Transpiler:
234
492
 
235
493
  return "{" + ", ".join(destructure_parts) + "}"
236
494
 
495
+ def _emit_default_expr(self, node: ast.expr) -> Expr:
496
+ """Emit defaults in defining-scope context."""
497
+ self._scope_stack.append(self._global_scope)
498
+ try:
499
+ return self.emit_expr(node)
500
+ finally:
501
+ self._scope_stack.pop()
502
+
237
503
  # --- Statements ----------------------------------------------------------
238
504
 
239
505
  def emit_stmt(self, node: ast.stmt) -> Stmt:
@@ -262,6 +528,7 @@ class Transpiler:
262
528
  "Only simple augmented assignments supported", node=node
263
529
  )
264
530
  target = node.target.id
531
+ self._require_local(target, node=node)
265
532
  op_type = type(node.op)
266
533
  if op_type not in ALLOWED_BINOPS:
267
534
  raise TranspileError(
@@ -296,22 +563,16 @@ class Transpiler:
296
563
  target = target_node.id
297
564
  value_expr = self.emit_expr(node.value)
298
565
 
299
- if target in self.locals:
300
- return Assign(target, value_expr)
301
- else:
302
- self.locals.add(target)
303
- return Assign(target, value_expr, declare="let")
566
+ self._require_local(target, node=node)
567
+ return Assign(target, value_expr)
304
568
 
305
569
  if isinstance(node, ast.AnnAssign):
306
570
  if not isinstance(node.target, ast.Name):
307
571
  raise TranspileError("Only simple annotated assignments supported")
308
572
  target = node.target.id
309
573
  value = Literal(None) if node.value is None else self.emit_expr(node.value)
310
- if target in self.locals:
311
- return Assign(target, value)
312
- else:
313
- self.locals.add(target)
314
- return Assign(target, value, declare="let")
574
+ self._require_local(target, node=node)
575
+ return Assign(target, value)
315
576
 
316
577
  if isinstance(node, ast.If):
317
578
  cond = self.emit_expr(node.test)
@@ -358,11 +619,8 @@ class Transpiler:
358
619
  assert isinstance(e, ast.Name)
359
620
  name = e.id
360
621
  sub = Subscript(Identifier(tmp_name), Literal(idx))
361
- if name in self.locals:
362
- stmts.append(Assign(name, sub))
363
- else:
364
- self.locals.add(name)
365
- stmts.append(Assign(name, sub, declare="let"))
622
+ self._require_local(name, node=target)
623
+ stmts.append(Assign(name, sub))
366
624
 
367
625
  return StmtSequence(stmts)
368
626
 
@@ -453,7 +711,7 @@ class Transpiler:
453
711
  "Only simple name targets supported in for-loop unpacking"
454
712
  )
455
713
  names.append(e.id)
456
- self.locals.add(e.id)
714
+ self._require_local(e.id, node=node)
457
715
  iter_expr = self.emit_expr(node.iter)
458
716
  body = [self.emit_stmt(s) for s in node.body]
459
717
  # Use array pattern for destructuring
@@ -464,7 +722,7 @@ class Transpiler:
464
722
  raise TranspileError("Only simple name targets supported in for-loops")
465
723
 
466
724
  target = node.target.id
467
- self.locals.add(target)
725
+ self._require_local(target, node=node)
468
726
  iter_expr = self.emit_expr(node.iter)
469
727
  body = [self.emit_stmt(s) for s in node.body]
470
728
  return ForOf(target, iter_expr, body)
@@ -474,31 +732,29 @@ class Transpiler:
474
732
  ) -> Stmt:
475
733
  """Emit a nested function definition."""
476
734
  name = node.name
477
- params = [arg.arg for arg in node.args.args]
478
-
479
- # Save current locals and extend with params
480
- saved_locals = set(self.locals)
481
- self.locals.update(params)
482
-
483
- # Skip docstrings and emit body
484
- body_stmts = node.body
485
- if (
486
- body_stmts
487
- and isinstance(body_stmts[0], ast.Expr)
488
- and isinstance(body_stmts[0].value, ast.Constant)
489
- and isinstance(body_stmts[0].value.value, str)
490
- ):
491
- body_stmts = body_stmts[1:]
735
+ params = _collect_param_names(node.args)
736
+ self._require_local(name, node=node)
492
737
 
493
- stmts: list[Stmt] = [self.emit_stmt(s) for s in body_stmts]
738
+ self._push_scope(node)
739
+ try:
740
+ # Skip docstrings and emit body
741
+ body_stmts = node.body
742
+ if (
743
+ body_stmts
744
+ and isinstance(body_stmts[0], ast.Expr)
745
+ and isinstance(body_stmts[0].value, ast.Constant)
746
+ and isinstance(body_stmts[0].value.value, str)
747
+ ):
748
+ body_stmts = body_stmts[1:]
494
749
 
495
- # Restore outer locals and add function name
496
- self.locals = saved_locals
497
- self.locals.add(name)
750
+ prelude = self._function_prelude(self._current_scope())
751
+ stmts: list[Stmt] = prelude + [self.emit_stmt(s) for s in body_stmts]
752
+ finally:
753
+ self._pop_scope()
498
754
 
499
755
  is_async = isinstance(node, ast.AsyncFunctionDef)
500
756
  fn = Function(params, stmts, is_async=is_async)
501
- return Assign(name, fn, declare="const")
757
+ return Assign(name, fn)
502
758
 
503
759
  def _emit_try(self, node: ast.Try) -> Stmt:
504
760
  """Emit a try/except/finally statement."""
@@ -517,7 +773,6 @@ class Transpiler:
517
773
  handler = node.handlers[0]
518
774
  if handler.name:
519
775
  catch_param = handler.name
520
- self.locals.add(catch_param)
521
776
  catch_body = [self.emit_stmt(s) for s in handler.body]
522
777
 
523
778
  # Handle finally
@@ -594,23 +849,21 @@ class Transpiler:
594
849
 
595
850
  if isinstance(node, ast.ListComp):
596
851
  return self._emit_comprehension_chain(
597
- node.generators, lambda: self.emit_expr(node.elt)
852
+ node, lambda: self.emit_expr(node.elt)
598
853
  )
599
854
 
600
855
  if isinstance(node, ast.GeneratorExp):
601
856
  return self._emit_comprehension_chain(
602
- node.generators, lambda: self.emit_expr(node.elt)
857
+ node, lambda: self.emit_expr(node.elt)
603
858
  )
604
859
 
605
860
  if isinstance(node, ast.SetComp):
606
- arr = self._emit_comprehension_chain(
607
- node.generators, lambda: self.emit_expr(node.elt)
608
- )
861
+ arr = self._emit_comprehension_chain(node, lambda: self.emit_expr(node.elt))
609
862
  return New(Identifier("Set"), [arr])
610
863
 
611
864
  if isinstance(node, ast.DictComp):
612
865
  pairs = self._emit_comprehension_chain(
613
- node.generators,
866
+ node,
614
867
  lambda: Array([self.emit_expr(node.key), self.emit_expr(node.value)]),
615
868
  )
616
869
  return New(Identifier("Map"), [pairs])
@@ -648,14 +901,14 @@ class Transpiler:
648
901
  """Emit a name reference."""
649
902
  name = node.id
650
903
 
651
- # Check deps first
904
+ # Local variable (current or enclosing scope)
905
+ if self._is_local(name):
906
+ return Identifier(name)
907
+
908
+ # Check deps
652
909
  if name in self.deps:
653
910
  return self.deps[name]
654
911
 
655
- # Local variable
656
- if name in self.locals:
657
- return Identifier(name)
658
-
659
912
  # Check builtins
660
913
  if name in BUILTINS:
661
914
  return BUILTINS[name]
@@ -1093,29 +1346,26 @@ class Transpiler:
1093
1346
 
1094
1347
  def _emit_lambda(self, node: ast.Lambda) -> Expr:
1095
1348
  """Emit a lambda expression as an arrow function."""
1096
- params = [arg.arg for arg in node.args.args]
1097
-
1098
- # Add params to locals temporarily
1099
- saved_locals = set(self.locals)
1100
- self.locals.update(params)
1101
-
1102
- body = self.emit_expr(node.body)
1349
+ params = _collect_param_names(node.args)
1103
1350
 
1104
- self.locals = saved_locals
1351
+ self._push_scope(node)
1352
+ try:
1353
+ body = self.emit_expr(node.body)
1354
+ finally:
1355
+ self._pop_scope()
1105
1356
 
1106
1357
  return Arrow(params, body)
1107
1358
 
1108
1359
  def _emit_comprehension_chain(
1109
1360
  self,
1110
- generators: list[ast.comprehension],
1361
+ node: ast.ListComp | ast.SetComp | ast.DictComp | ast.GeneratorExp,
1111
1362
  build_last: Callable[[], Expr],
1112
1363
  ) -> Expr:
1113
1364
  """Build a flatMap/map chain for comprehensions."""
1365
+ generators = node.generators
1114
1366
  if len(generators) == 0:
1115
1367
  raise TranspileError("Empty comprehension")
1116
1368
 
1117
- saved_locals = set(self.locals)
1118
-
1119
1369
  def build_chain(gen_index: int) -> Expr:
1120
1370
  gen = generators[gen_index]
1121
1371
  if gen.is_async:
@@ -1139,7 +1389,7 @@ class Transpiler:
1139
1389
  )
1140
1390
 
1141
1391
  for nm in names:
1142
- self.locals.add(nm)
1392
+ self._current_scope().locals.add(nm)
1143
1393
 
1144
1394
  base = iter_expr
1145
1395
 
@@ -1159,10 +1409,11 @@ class Transpiler:
1159
1409
  inner = build_chain(gen_index + 1)
1160
1410
  return Call(Member(base, "flatMap"), [Arrow(params, inner)])
1161
1411
 
1412
+ self._push_scope(node)
1162
1413
  try:
1163
1414
  return build_chain(0)
1164
1415
  finally:
1165
- self.locals = saved_locals
1416
+ self._pop_scope()
1166
1417
 
1167
1418
 
1168
1419
  def transpile(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pulse-framework
3
- Version: 0.1.73
3
+ Version: 0.1.75
4
4
  Summary: Pulse - Full-stack framework for building real-time React applications in Python
5
5
  Requires-Dist: fastapi>=0.128.0
6
6
  Requires-Dist: uvicorn>=0.24.0
@@ -48,27 +48,44 @@ pulse/hooks/runtime.py,sha256=ogrm4Prvr9ZNaBb5bLfZBHrzbJuYe1zKpIPkbdnIzsw,12286
48
48
  pulse/hooks/setup.py,sha256=NcQPKnMV5dO0vUsWi4u9c9LB0wqFstrtiPGdvihtGiQ,6872
49
49
  pulse/hooks/stable.py,sha256=hLCOl_oAbgdNwiaWwwUTk7ZsHvMqXFFozFztJZMyGbQ,3627
50
50
  pulse/hooks/state.py,sha256=zRFlcOUdl-SBkJ-EzVXRLrLXzAc4-uRzgH4hD9rM1oU,5251
51
- pulse/js/__init__.py,sha256=tj1A6-eR5WS83UNgHb3Dw23m37oJsEuyV0ezUB6kXbg,3636
52
- pulse/js/__init__.pyi,sha256=WN22WsJB-XFk6auL9zklwG2Kof3zeOsc56A56dJ3MWg,3097
51
+ pulse/js/__init__.py,sha256=csEWvFon_ayAiR6OVQl2wnukaLWLK1_PPodVlcY_EvY,5062
52
+ pulse/js/__init__.pyi,sha256=DCgO3uNh6dQLVd9QD3I-LyiPP9VrtE7MZYYHr-8EvVg,5479
53
53
  pulse/js/_types.py,sha256=F4Go2JtJ2dbxq1fXpc2ablG_nyvhvHzOlZLlEv0VmyU,7421
54
+ pulse/js/abort_controller.py,sha256=nKiUgS_uy2Rgh-MNG7fcGIm8Qd6g7hNV_UVk7OgK3qg,1161
54
55
  pulse/js/array.py,sha256=_tC6QZlflWCXOXXUMMtowM3UK7iDWAtFM8BKqR5rjKk,8883
56
+ pulse/js/array_buffer.py,sha256=-iuiSZuv-rx3d0jpQtQYZLXZ2nLuMF93QrQBO-HXv5o,4100
57
+ pulse/js/blob.py,sha256=XiI4g_fKaKtB8OPzS6D4rFG0fRBZlCl9kbO7a5IFPPk,981
55
58
  pulse/js/console.py,sha256=A-GNKEnPby10gdcTdYsBPVfz4m94PYzTXRwGhfaPRpc,1775
59
+ pulse/js/crypto.py,sha256=Atxtc2oqb4xnW9nQV3ruamQhCAl2O_H2XiECspN1JvI,1245
60
+ pulse/js/custom_event.py,sha256=SxtzPQJwgSXRmesd3SiaVdCGYHsFcrnAiPZA63YuunA,901
56
61
  pulse/js/date.py,sha256=qJjdwupuUtKS95u8N8C8FKMKOIB8qjVMsYA3VYfe-tA,3363
57
62
  pulse/js/document.py,sha256=SBinVGfb05jFpeyxAE0yk5Z__dkdW_mFsTI-rvgc-S8,3004
63
+ pulse/js/dom_parser.py,sha256=0qRlAHVr1gDphCPUOSJRcZR94giJF6JmsWOJv4I6p80,818
58
64
  pulse/js/error.py,sha256=v0_DmpN5ESt_CJTrIYfy8980eerjK8mHhQatNV_1M_8,2611
65
+ pulse/js/fetch_api.py,sha256=-4qy5DkQcCeE9CvFMtq-by-WgA7PirgOrmgMflMsluQ,2342
66
+ pulse/js/file.py,sha256=LDoAUXyq82VUULVkIeSjcIj1Vvy2hCi_LRUWh8THyP8,1177
67
+ pulse/js/file_reader.py,sha256=-Y5rfjb2j9tQ-NDX-mWgERC6Alfllh2VvRr6rzXoII0,664
68
+ pulse/js/form_data.py,sha256=_NKZZmD4G4gHsq-QKFMAFwU73ZatGK06p6_oUdQnh_U,1258
69
+ pulse/js/intersection_observer.py,sha256=ZcNV1qyiXjKPOKz5zUQTMZ3oCpfxxSRxLCEDHS_5aKY,1672
70
+ pulse/js/intl.py,sha256=Y_a1YvdQPzOpJAnpPiyM7Ip03L5mh-noChRDeDneVjU,2034
59
71
  pulse/js/json.py,sha256=P8nxOANjIxrzUA1XkBrd0SmNyAGyB3pVXZDPnA1OKks,1908
60
72
  pulse/js/map.py,sha256=bhw75CUMIearH4JACCs9zAffdzfla3Rae7SKGcCLGoc,2243
61
73
  pulse/js/math.py,sha256=OBbMlgoa6ZHLDgmXGNKMj5wYrvroV5ICIx-VsSE5_II,1757
74
+ pulse/js/mutation_observer.py,sha256=7Ai74vHZFkAnVS-OrGYRanY9TpJZmHJ4PrKpz8jmTTU,1831
62
75
  pulse/js/navigator.py,sha256=2QWSr9xyyBfgd76P472qmayXQRYXIEo-b8zLzvfhHfg,1517
63
76
  pulse/js/number.py,sha256=fX2M6hZ5ry2FPsYaHhGlqgO6reBEXw7C-gtu0-8_Zyw,1262
64
77
  pulse/js/obj.py,sha256=8JG9OZZ1CNqAFoMTdYtxWhTmb6zs1BqxC-nLT7KYMF8,2030
65
78
  pulse/js/object.py,sha256=95WvnGWgB-PL-D7l12UgdxNy_fxO5sJXool3Rx5ahUQ,4433
79
+ pulse/js/performance_observer.py,sha256=uletaqnJ6kvJqFSSFtmNo0j--FduK4uZHd8cfRqeN3A,1156
66
80
  pulse/js/promise.py,sha256=vBXcL-U9BuZN-q1jbYhyzQaOL2niDPw4LsD7q7Y_yco,4670
67
81
  pulse/js/pulse.py,sha256=m-LgqwhYygVBj7GzjeO-uo8fK5ThyVe7c3QvOJt_vc0,2962
68
82
  pulse/js/react.py,sha256=eRMrgM8RsoAIn2lcHDoUYas3l4tImLOW51dwmw9AxQU,12057
69
83
  pulse/js/regexp.py,sha256=qO-3nmt7uGN7V_bwimPCN-2RSsPfE6YiY7G1MjoP3YY,1055
84
+ pulse/js/resize_observer.py,sha256=MN0pqnBETmI7bSrWT1bus4_vTZKmJ0jwBoW-cYQWoT4,1162
70
85
  pulse/js/set.py,sha256=omG3g-25GRHxgoKISSB4x-M8UDFlaXtFV9cSIpd5uB0,3017
71
86
  pulse/js/string.py,sha256=VsvDF_ve8R9QIiBdDotLP2KpCKwmpEfGgRQWckOCmHk,813
87
+ pulse/js/text_encoding.py,sha256=5Qvl4XRva9m6tz9NKlv9Nej-O92epMG-y_bu6vCNHwI,1291
88
+ pulse/js/url.py,sha256=-sOthAlPOhJvkXh4hhNLOuWbPKd_ICnG7u--yHDPzY4,2200
72
89
  pulse/js/weakmap.py,sha256=HACZEZ8EZk1xoaCmTXk__opvJLxlJ9_0U3y-01KQkHU,1412
73
90
  pulse/js/weakset.py,sha256=jerMG9ubroR29HvOLIm6lkLxMj-GGWbiE57U9F6zRuQ,1256
74
91
  pulse/js/window.py,sha256=yC1BjyH2jqp1x-CXJCUFta-ASyZ5668ozQ0AmAjZcxA,4097
@@ -101,13 +118,13 @@ pulse/state/property.py,sha256=pitudvCGBNqK6lePdPrs4Inyy7szo8qcR_0BI30veek,6274
101
118
  pulse/state/query_param.py,sha256=7faf244_KJ3yrsBimKTBlNLg6wP96FUuWoZl40oxpyY,14478
102
119
  pulse/state/state.py,sha256=_4DcB-og2s5Ui01kDx9HzpNwmAVD_pdCLB0TfYbcnzM,11603
103
120
  pulse/test_helpers.py,sha256=4iO5Ymy3SMvSjh-UaAaSdqm1I_SAJMNjdY2iYVro5f8,436
104
- pulse/transpiler/__init__.py,sha256=wDDnzqxgHpp_OLtcgyrJEg2jVoTnFIe3SSSTOsMDW8w,4700
121
+ pulse/transpiler/__init__.py,sha256=0UqeEQ2dMD2tDDkzTASv-StQfKZkPuSvbYTqjkNk-3A,4895
105
122
  pulse/transpiler/assets.py,sha256=digd5hKYPEgLOzMtDBHULX3Adj1sfngdvnx3quQmgPY,2299
106
123
  pulse/transpiler/builtins.py,sha256=QZrow7XJ2wxGMAE-mgZmaUD03egOnXCbikOg8yMx9vQ,30807
107
124
  pulse/transpiler/dynamic_import.py,sha256=1AmBl6agGSoTZBp_94seXH733fewLOULUix9BOBPtKI,3372
108
125
  pulse/transpiler/emit_context.py,sha256=GyK6VdsBSTVIewQRhBagaV0hlqLTlPZ1i8EAZGi8SaY,1321
109
126
  pulse/transpiler/errors.py,sha256=LSBjLBnMglbl2D94p9JR4y-3jDefk6iHSlUVBaBOTu4,2823
110
- pulse/transpiler/function.py,sha256=a871LZFergCmjs1vr-XlOx4eU1FQKAuYxSLJej-LHHc,17036
127
+ pulse/transpiler/function.py,sha256=8-WZC2VcPTGfFeWWQpCltOVPLyr4f1H8pWoCvSnI654,18105
111
128
  pulse/transpiler/id.py,sha256=CdgA1NndBpZjv0Hp4XiYbKn7wi-x4zWsFSjEiViKxVk,434
112
129
  pulse/transpiler/imports.py,sha256=gWLjRr9jakbUzBGDEepE2RI5Xn_UZwOD4TmlqjNIapM,10302
113
130
  pulse/transpiler/js_module.py,sha256=OcIgmrfiA6Hh6aukzgkyX63KsVSHdLzx5ezdKiJFUaQ,11093
@@ -118,15 +135,16 @@ pulse/transpiler/modules/math.py,sha256=8gjvdYTMqtuOnXrvX_Lwuo0ywAdSl7cpss4TMk6m
118
135
  pulse/transpiler/modules/pulse/__init__.py,sha256=TfMsiiB53ZFlxdNl7jfCAiMZs-vSRUTxUmqzkLTj-po,91
119
136
  pulse/transpiler/modules/pulse/tags.py,sha256=FMN1mWMlnsXa2qO6VmXxUAhFn1uOfGoKPQOjH4ZPlRE,6218
120
137
  pulse/transpiler/modules/typing.py,sha256=J9QCkXE6zzwMjiprX2q1BtK-iKLIiS21sQ78JH4RSMc,1716
121
- pulse/transpiler/nodes.py,sha256=vebA81QXkWoJMygX2CHH_94azKPRATaB6eBs5wdX4rE,52420
138
+ pulse/transpiler/nodes.py,sha256=ObdCFIEvtKMVRO8iy1hIN4L-vC4yPqRvhPS6E344-bE,52673
139
+ pulse/transpiler/parse.py,sha256=uz_KDnjmjzFSjGtVKRznWg95P0NHM8CafWgvqrqJcOs,1622
122
140
  pulse/transpiler/py_module.py,sha256=um4BYLrbs01bpgv2LEBHTbhXXh8Bs174c3ygv5tHHOg,4410
123
- pulse/transpiler/transpiler.py,sha256=pxNFVnJB_zpUnp12cfzeOqUINAb1ZKhlU2E1gYUE6mk,35752
141
+ pulse/transpiler/transpiler.py,sha256=bu33-wGNqHGheT_ZqMnQgEARyPG6xyOvuLuixjxIZnI,42761
124
142
  pulse/transpiler/vdom.py,sha256=Bf1yw10hQl8BXa6rhr5byRa5ua3qgRsVGNgEtQneA2A,6460
125
143
  pulse/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
126
144
  pulse/types/event_handler.py,sha256=psQCydj-WEtBcFU5JU4mDwvyzkW8V2O0g_VFRU2EOHI,1618
127
145
  pulse/user_session.py,sha256=nsnsMgqq2xGJZLpbHRMHUHcLrElMP8WcA4gjGMrcoBk,10208
128
146
  pulse/version.py,sha256=711vaM1jVIQPgkisGgKZqwmw019qZIsc_QTae75K2pg,1895
129
- pulse_framework-0.1.73.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
130
- pulse_framework-0.1.73.dist-info/entry_points.txt,sha256=i7aohd3QaPu5IcuGKKvsQQEiMYMe5HcF56QEsaLVO64,46
131
- pulse_framework-0.1.73.dist-info/METADATA,sha256=PIqxEHW98zMJlT1C_cLNisDzX73GDvGKFW8e4UtVTfk,8299
132
- pulse_framework-0.1.73.dist-info/RECORD,,
147
+ pulse_framework-0.1.75.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
148
+ pulse_framework-0.1.75.dist-info/entry_points.txt,sha256=i7aohd3QaPu5IcuGKKvsQQEiMYMe5HcF56QEsaLVO64,46
149
+ pulse_framework-0.1.75.dist-info/METADATA,sha256=Y2M3HpMari75ZADpqGSxEfyP5YGCnRS2AkZ3tE3lmpA,8299
150
+ pulse_framework-0.1.75.dist-info/RECORD,,