pulse-framework 0.1.61__tar.gz → 0.1.63__tar.gz
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.
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/PKG-INFO +1 -1
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/pyproject.toml +1 -1
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/__init__.py +1 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/app.py +3 -3
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/cli/dependencies.py +7 -16
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/component.py +1 -1
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/obj.py +1 -2
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/react.py +1 -2
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/renderer.py +7 -4
- pulse_framework-0.1.63/src/pulse/requirements.py +47 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/assets.py +16 -1
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/dynamic_import.py +2 -3
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/function.py +4 -4
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/imports.py +24 -3
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/js_module.py +2 -3
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/modules/pulse/tags.py +1 -2
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/modules/typing.py +1 -2
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/nodes.py +77 -34
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/py_module.py +1 -2
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/README.md +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/_examples.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/channel.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/cli/__init__.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/cli/cmd.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/cli/folder_lock.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/cli/helpers.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/cli/logging.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/cli/models.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/cli/packages.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/cli/processes.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/cli/secrets.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/cli/uvicorn_log_config.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/code_analysis.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/codegen/__init__.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/codegen/codegen.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/codegen/templates/__init__.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/codegen/templates/layout.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/codegen/templates/route.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/codegen/templates/routes_ts.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/codegen/utils.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/components/__init__.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/components/for_.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/components/if_.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/components/react_router.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/context.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/cookies.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/decorators.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/dom/__init__.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/dom/elements.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/dom/events.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/dom/props.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/dom/svg.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/dom/tags.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/dom/tags.pyi +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/env.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/form.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/helpers.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/hooks/__init__.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/hooks/core.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/hooks/effects.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/hooks/init.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/hooks/runtime.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/hooks/setup.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/hooks/stable.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/hooks/state.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/__init__.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/__init__.pyi +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/_types.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/array.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/console.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/date.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/document.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/error.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/json.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/map.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/math.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/navigator.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/number.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/object.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/promise.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/pulse.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/regexp.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/set.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/string.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/weakmap.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/weakset.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/js/window.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/messages.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/middleware.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/plugin.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/proxy.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/py.typed +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/queries/__init__.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/queries/client.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/queries/common.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/queries/effect.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/queries/infinite_query.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/queries/mutation.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/queries/protocol.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/queries/query.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/queries/store.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/react_component.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/reactive.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/reactive_extensions.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/render_session.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/request.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/routing.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/serializer.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/state.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/test_helpers.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/__init__.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/builtins.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/emit_context.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/errors.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/id.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/modules/__init__.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/modules/asyncio.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/modules/json.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/modules/math.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/modules/pulse/__init__.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/transpiler.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/vdom.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/types/__init__.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/types/event_handler.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/user_session.py +0 -0
- {pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/version.py +0 -0
|
@@ -1410,6 +1410,7 @@ from pulse.render_session import run_js as run_js
|
|
|
1410
1410
|
|
|
1411
1411
|
# Request
|
|
1412
1412
|
from pulse.request import PulseRequest as PulseRequest
|
|
1413
|
+
from pulse.requirements import require as require
|
|
1413
1414
|
from pulse.routing import Layout as Layout
|
|
1414
1415
|
from pulse.routing import Route as Route
|
|
1415
1416
|
from pulse.routing import RouteInfo as RouteInfo
|
|
@@ -147,7 +147,7 @@ class App:
|
|
|
147
147
|
and lifecycle hooks.
|
|
148
148
|
cookie: Session cookie configuration.
|
|
149
149
|
session_store: Session storage backend. Defaults to CookieSessionStore.
|
|
150
|
-
server_address: Public server URL.
|
|
150
|
+
server_address: Public server URL. Used only in ci/prod.
|
|
151
151
|
dev_server_address: Development server URL. Defaults to
|
|
152
152
|
"http://localhost:8000".
|
|
153
153
|
internal_server_address: Internal URL for server-side loader fetches.
|
|
@@ -243,8 +243,8 @@ class App:
|
|
|
243
243
|
self.env = envvars.pulse_env
|
|
244
244
|
self.mode = mode
|
|
245
245
|
self.status = AppStatus.created
|
|
246
|
-
# Persist the server address for use by sessions (API calls, etc.)
|
|
247
|
-
self.server_address = server_address
|
|
246
|
+
# Persist the server address for use by sessions (API calls, etc.) in ci/prod.
|
|
247
|
+
self.server_address = server_address if self.env in ("ci", "prod") else None
|
|
248
248
|
# Development server address (used in dev mode)
|
|
249
249
|
self.dev_server_address = dev_server_address
|
|
250
250
|
# Optional internal address used by server-side loader fetches
|
|
@@ -11,11 +11,10 @@ from pulse.cli.packages import (
|
|
|
11
11
|
is_workspace_spec,
|
|
12
12
|
load_package_json,
|
|
13
13
|
parse_dependency_spec,
|
|
14
|
-
parse_install_spec,
|
|
15
14
|
resolve_versions,
|
|
16
15
|
spec_satisfies,
|
|
17
16
|
)
|
|
18
|
-
from pulse.
|
|
17
|
+
from pulse.requirements import get_requirements
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
def convert_pep440_to_semver(python_version: str) -> str:
|
|
@@ -98,20 +97,12 @@ def get_required_dependencies(
|
|
|
98
97
|
"pulse-ui-client": [pulse_version],
|
|
99
98
|
}
|
|
100
99
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
# We might want to be more lenient here or at least log it,
|
|
108
|
-
# but following existing pattern of raising DependencyError
|
|
109
|
-
raise DependencyError(str(exc)) from None
|
|
110
|
-
if spec:
|
|
111
|
-
name_only, ver = parse_dependency_spec(spec)
|
|
112
|
-
constraints.setdefault(name_only, []).append(ver)
|
|
113
|
-
if imp.version:
|
|
114
|
-
constraints.setdefault(name_only, []).append(imp.version)
|
|
100
|
+
for src, version in get_requirements():
|
|
101
|
+
name_only, ver_in_src = parse_dependency_spec(src)
|
|
102
|
+
if ver_in_src:
|
|
103
|
+
constraints.setdefault(name_only, []).append(ver_in_src)
|
|
104
|
+
if version:
|
|
105
|
+
constraints.setdefault(name_only, []).append(version)
|
|
115
106
|
|
|
116
107
|
try:
|
|
117
108
|
resolved = resolve_versions(constraints)
|
|
@@ -112,7 +112,7 @@ class Component(Generic[P]):
|
|
|
112
112
|
flattened = flatten_children(
|
|
113
113
|
args, # pyright: ignore[reportArgumentType]
|
|
114
114
|
parent_name=f"<{self.name}>",
|
|
115
|
-
warn_stacklevel=
|
|
115
|
+
warn_stacklevel=None,
|
|
116
116
|
)
|
|
117
117
|
args = tuple(flattened) # pyright: ignore[reportAssignmentType]
|
|
118
118
|
|
|
@@ -30,7 +30,6 @@ from typing import TYPE_CHECKING, override
|
|
|
30
30
|
|
|
31
31
|
from pulse.transpiler.errors import TranspileError
|
|
32
32
|
from pulse.transpiler.nodes import Expr, Object, Spread, spread_dict
|
|
33
|
-
from pulse.transpiler.vdom import VDOMNode
|
|
34
33
|
|
|
35
34
|
# TYPE_CHECKING avoids import cycle: Transpiler -> nodes -> Expr -> obj -> Transpiler
|
|
36
35
|
if TYPE_CHECKING:
|
|
@@ -53,7 +52,7 @@ class ObjTransformer(Expr):
|
|
|
53
52
|
raise TypeError("obj cannot be emitted directly - must be called")
|
|
54
53
|
|
|
55
54
|
@override
|
|
56
|
-
def render(self)
|
|
55
|
+
def render(self):
|
|
57
56
|
raise TypeError("obj cannot be rendered - must be called")
|
|
58
57
|
|
|
59
58
|
@override
|
|
@@ -32,7 +32,6 @@ from pulse.transpiler.nodes import Call as _Call
|
|
|
32
32
|
from pulse.transpiler.nodes import Expr as _Expr
|
|
33
33
|
from pulse.transpiler.nodes import Jsx as _Jsx
|
|
34
34
|
from pulse.transpiler.nodes import Node as _PulseNode
|
|
35
|
-
from pulse.transpiler.vdom import VDOMNode as _VDOMNode
|
|
36
35
|
|
|
37
36
|
if _TYPE_CHECKING:
|
|
38
37
|
from pulse.transpiler.transpiler import Transpiler as _Transpiler
|
|
@@ -432,7 +431,7 @@ class _LazyComponentFactory(_Expr):
|
|
|
432
431
|
self._import.emit(out)
|
|
433
432
|
|
|
434
433
|
@_override
|
|
435
|
-
def render(self)
|
|
434
|
+
def render(self):
|
|
436
435
|
raise TypeError("lazy cannot be rendered to VDOM")
|
|
437
436
|
|
|
438
437
|
@_override
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import inspect
|
|
4
4
|
from collections.abc import Callable, Iterable
|
|
5
5
|
from dataclasses import dataclass
|
|
6
|
+
from types import NoneType
|
|
6
7
|
from typing import Any, NamedTuple, TypeAlias, cast
|
|
7
8
|
|
|
8
9
|
from pulse.helpers import values_equal
|
|
@@ -27,7 +28,6 @@ from pulse.transpiler.vdom import (
|
|
|
27
28
|
UpdatePropsDelta,
|
|
28
29
|
UpdatePropsOperation,
|
|
29
30
|
VDOMElement,
|
|
30
|
-
VDOMExpr,
|
|
31
31
|
VDOMNode,
|
|
32
32
|
VDOMOperation,
|
|
33
33
|
VDOMPropValue,
|
|
@@ -442,17 +442,20 @@ class Renderer:
|
|
|
442
442
|
# Expression + tag rendering
|
|
443
443
|
# ------------------------------------------------------------------
|
|
444
444
|
|
|
445
|
-
def render_tag(self, tag: str | Expr)
|
|
445
|
+
def render_tag(self, tag: str | Expr):
|
|
446
446
|
if isinstance(tag, str):
|
|
447
447
|
return tag
|
|
448
448
|
|
|
449
449
|
return self.register_component_expr(tag)
|
|
450
450
|
|
|
451
|
-
def register_component_expr(self, expr: Expr)
|
|
451
|
+
def register_component_expr(self, expr: Expr):
|
|
452
452
|
ref = registry_ref(expr)
|
|
453
453
|
if ref is not None:
|
|
454
454
|
return f"{MOUNT_PREFIX}{ref['key']}"
|
|
455
|
-
|
|
455
|
+
tag = expr.render()
|
|
456
|
+
if isinstance(tag, (int, float, bool, NoneType)):
|
|
457
|
+
raise TypeError(f"Invalid element tag: {tag}")
|
|
458
|
+
return tag
|
|
456
459
|
|
|
457
460
|
# ------------------------------------------------------------------
|
|
458
461
|
# Unmount helper
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
|
|
5
|
+
_REQUIREMENTS: list[tuple[str, str]] = []
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def add_requirement(name: str, version: str) -> None:
|
|
9
|
+
if not name or not version:
|
|
10
|
+
return
|
|
11
|
+
_REQUIREMENTS.append((name, version))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def register_requirements(packages: Mapping[str, str]) -> None:
|
|
15
|
+
for name, version in packages.items():
|
|
16
|
+
if not name or not version:
|
|
17
|
+
continue
|
|
18
|
+
add_requirement(name, version)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_requirements() -> list[tuple[str, str]]:
|
|
22
|
+
return list(_REQUIREMENTS)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def clear_requirements() -> None:
|
|
26
|
+
_REQUIREMENTS.clear()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def require(packages: Mapping[str, str]) -> None:
|
|
30
|
+
"""Register npm package version requirements for dependency syncing."""
|
|
31
|
+
if not isinstance(packages, Mapping):
|
|
32
|
+
raise TypeError("require expects a mapping of package names to versions")
|
|
33
|
+
if not packages:
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
normalized: dict[str, str] = {}
|
|
37
|
+
for name, version in packages.items():
|
|
38
|
+
if not isinstance(name, str) or not name.strip():
|
|
39
|
+
raise TypeError("require expects non-empty package names")
|
|
40
|
+
if not isinstance(version, str) or not version.strip():
|
|
41
|
+
raise TypeError(f"require expects a version string for {name!r}")
|
|
42
|
+
normalized[name.strip()] = version.strip()
|
|
43
|
+
|
|
44
|
+
register_requirements(normalized)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
__all__ = ["require"]
|
|
@@ -13,6 +13,15 @@ from pathlib import Path
|
|
|
13
13
|
from pulse.transpiler.emit_context import EmitContext
|
|
14
14
|
from pulse.transpiler.id import next_id
|
|
15
15
|
|
|
16
|
+
_CSS_MODULE_EXTS = (
|
|
17
|
+
".css",
|
|
18
|
+
".scss",
|
|
19
|
+
".sass",
|
|
20
|
+
".less",
|
|
21
|
+
".styl",
|
|
22
|
+
".stylus",
|
|
23
|
+
)
|
|
24
|
+
|
|
16
25
|
|
|
17
26
|
@dataclass(slots=True)
|
|
18
27
|
class LocalAsset:
|
|
@@ -23,7 +32,13 @@ class LocalAsset:
|
|
|
23
32
|
|
|
24
33
|
@property
|
|
25
34
|
def asset_filename(self) -> str:
|
|
26
|
-
"""Filename in assets folder: stem_id.ext"""
|
|
35
|
+
"""Filename in assets folder: stem_id.ext (preserve .module.*)."""
|
|
36
|
+
name = self.source_path.name
|
|
37
|
+
for ext in _CSS_MODULE_EXTS:
|
|
38
|
+
module_suffix = f".module{ext}"
|
|
39
|
+
if name.endswith(module_suffix):
|
|
40
|
+
base = name[: -len(module_suffix)]
|
|
41
|
+
return f"{base}_{self.id}{module_suffix}"
|
|
27
42
|
return f"{self.source_path.stem}_{self.id}{self.source_path.suffix}"
|
|
28
43
|
|
|
29
44
|
def import_path(self) -> str:
|
|
@@ -28,7 +28,6 @@ from pulse.transpiler.assets import LocalAsset, register_local_asset
|
|
|
28
28
|
from pulse.transpiler.errors import TranspileError
|
|
29
29
|
from pulse.transpiler.imports import is_local_path, resolve_local_path
|
|
30
30
|
from pulse.transpiler.nodes import Expr, Member
|
|
31
|
-
from pulse.transpiler.vdom import VDOMNode
|
|
32
31
|
|
|
33
32
|
if TYPE_CHECKING:
|
|
34
33
|
from pulse.transpiler.transpiler import Transpiler
|
|
@@ -56,7 +55,7 @@ class DynamicImport(Expr):
|
|
|
56
55
|
out.append(f'import("{self.src}")')
|
|
57
56
|
|
|
58
57
|
@override
|
|
59
|
-
def render(self)
|
|
58
|
+
def render(self):
|
|
60
59
|
raise TypeError("DynamicImport cannot be rendered to VDOM")
|
|
61
60
|
|
|
62
61
|
@override
|
|
@@ -84,7 +83,7 @@ class DynamicImportFn(Expr):
|
|
|
84
83
|
)
|
|
85
84
|
|
|
86
85
|
@override
|
|
87
|
-
def render(self)
|
|
86
|
+
def render(self):
|
|
88
87
|
raise TypeError("import_ cannot be rendered to VDOM")
|
|
89
88
|
|
|
90
89
|
@override
|
|
@@ -39,7 +39,7 @@ from pulse.transpiler.nodes import (
|
|
|
39
39
|
to_js_identifier,
|
|
40
40
|
)
|
|
41
41
|
from pulse.transpiler.transpiler import Transpiler
|
|
42
|
-
from pulse.transpiler.vdom import
|
|
42
|
+
from pulse.transpiler.vdom import VDOMExpr
|
|
43
43
|
|
|
44
44
|
Args = TypeVarTuple("Args")
|
|
45
45
|
P = ParamSpec("P")
|
|
@@ -114,7 +114,7 @@ class Constant(Expr):
|
|
|
114
114
|
out.append(self.js_name)
|
|
115
115
|
|
|
116
116
|
@override
|
|
117
|
-
def render(self) ->
|
|
117
|
+
def render(self) -> VDOMExpr:
|
|
118
118
|
"""Render as a registry reference."""
|
|
119
119
|
return {"t": "ref", "key": self.id}
|
|
120
120
|
|
|
@@ -226,7 +226,7 @@ class JsFunction(Expr, Generic[*Args, R]):
|
|
|
226
226
|
out.append(self.js_name)
|
|
227
227
|
|
|
228
228
|
@override
|
|
229
|
-
def render(self) ->
|
|
229
|
+
def render(self) -> VDOMExpr:
|
|
230
230
|
"""Render as a registry reference."""
|
|
231
231
|
return {"t": "ref", "key": self.id}
|
|
232
232
|
|
|
@@ -314,7 +314,7 @@ class JsxFunction(Expr, Generic[P, R]):
|
|
|
314
314
|
out.append(self.js_name)
|
|
315
315
|
|
|
316
316
|
@override
|
|
317
|
-
def render(self) ->
|
|
317
|
+
def render(self) -> VDOMExpr:
|
|
318
318
|
"""Render as a registry reference."""
|
|
319
319
|
return {"t": "ref", "key": self.id}
|
|
320
320
|
|
|
@@ -14,12 +14,13 @@ from typing import (
|
|
|
14
14
|
)
|
|
15
15
|
from typing import Literal as Lit
|
|
16
16
|
|
|
17
|
-
from pulse.cli.packages import pick_more_specific
|
|
17
|
+
from pulse.cli.packages import parse_dependency_spec, pick_more_specific
|
|
18
|
+
from pulse.requirements import add_requirement, clear_requirements
|
|
18
19
|
from pulse.transpiler.assets import LocalAsset, register_local_asset
|
|
19
20
|
from pulse.transpiler.errors import TranspileError
|
|
20
21
|
from pulse.transpiler.id import next_id
|
|
21
22
|
from pulse.transpiler.nodes import Call, Expr, to_js_identifier
|
|
22
|
-
from pulse.transpiler.vdom import
|
|
23
|
+
from pulse.transpiler.vdom import VDOMExpr
|
|
23
24
|
|
|
24
25
|
_P = ParamSpec("_P")
|
|
25
26
|
_R = TypeVar("_R")
|
|
@@ -131,6 +132,14 @@ _ImportKey: TypeAlias = tuple[str, str, str, bool]
|
|
|
131
132
|
_IMPORT_REGISTRY: dict[_ImportKey, "Import"] = {}
|
|
132
133
|
|
|
133
134
|
|
|
135
|
+
def _is_alias_path(path: str) -> bool:
|
|
136
|
+
return path.startswith("@/") or path.startswith("~/")
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _is_url(path: str) -> bool:
|
|
140
|
+
return path.startswith("http://") or path.startswith("https://")
|
|
141
|
+
|
|
142
|
+
|
|
134
143
|
def get_registered_imports() -> list["Import"]:
|
|
135
144
|
"""Get all registered imports."""
|
|
136
145
|
return list(_IMPORT_REGISTRY.values())
|
|
@@ -139,6 +148,7 @@ def get_registered_imports() -> list["Import"]:
|
|
|
139
148
|
def clear_import_registry() -> None:
|
|
140
149
|
"""Clear the import registry."""
|
|
141
150
|
_IMPORT_REGISTRY.clear()
|
|
151
|
+
clear_requirements()
|
|
142
152
|
|
|
143
153
|
|
|
144
154
|
@dataclass(slots=True, init=False)
|
|
@@ -240,6 +250,17 @@ class Import(Expr):
|
|
|
240
250
|
asset = register_local_asset(resolved)
|
|
241
251
|
import_src = str(resolved)
|
|
242
252
|
|
|
253
|
+
if (
|
|
254
|
+
not is_local_path(import_src)
|
|
255
|
+
and not _is_alias_path(import_src)
|
|
256
|
+
and not _is_url(import_src)
|
|
257
|
+
):
|
|
258
|
+
name_only, ver_in_src = parse_dependency_spec(import_src)
|
|
259
|
+
if ver_in_src:
|
|
260
|
+
add_requirement(name_only, ver_in_src)
|
|
261
|
+
if version:
|
|
262
|
+
add_requirement(name_only, version)
|
|
263
|
+
|
|
243
264
|
self.name = name
|
|
244
265
|
self.src = import_src
|
|
245
266
|
self.kind = kind
|
|
@@ -320,7 +341,7 @@ class Import(Expr):
|
|
|
320
341
|
out.append(self.js_name)
|
|
321
342
|
|
|
322
343
|
@override
|
|
323
|
-
def render(self) ->
|
|
344
|
+
def render(self) -> VDOMExpr:
|
|
324
345
|
"""Render as a registry reference."""
|
|
325
346
|
return {"t": "ref", "key": self.id}
|
|
326
347
|
|
|
@@ -23,7 +23,6 @@ from pulse.transpiler.nodes import (
|
|
|
23
23
|
New,
|
|
24
24
|
)
|
|
25
25
|
from pulse.transpiler.transpiler import Transpiler
|
|
26
|
-
from pulse.transpiler.vdom import VDOMNode
|
|
27
26
|
|
|
28
27
|
_MODULE_DUNDERS = frozenset(
|
|
29
28
|
{
|
|
@@ -58,7 +57,7 @@ class Class(Expr):
|
|
|
58
57
|
self.ctor.emit(out)
|
|
59
58
|
|
|
60
59
|
@override
|
|
61
|
-
def render(self)
|
|
60
|
+
def render(self):
|
|
62
61
|
return self.ctor.render()
|
|
63
62
|
|
|
64
63
|
@override
|
|
@@ -110,7 +109,7 @@ class JsModule(Expr):
|
|
|
110
109
|
raise TypeError(f"{label} cannot be emitted directly - access an attribute")
|
|
111
110
|
|
|
112
111
|
@override
|
|
113
|
-
def render(self)
|
|
112
|
+
def render(self):
|
|
114
113
|
label = self.py_name or self.name or "JsModule"
|
|
115
114
|
raise TypeError(f"{label} cannot be rendered directly - access an attribute")
|
|
116
115
|
|
{pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/modules/pulse/tags.py
RENAMED
|
@@ -28,7 +28,6 @@ from pulse.transpiler.nodes import (
|
|
|
28
28
|
)
|
|
29
29
|
from pulse.transpiler.py_module import PyModule
|
|
30
30
|
from pulse.transpiler.transpiler import Transpiler
|
|
31
|
-
from pulse.transpiler.vdom import VDOMNode
|
|
32
31
|
|
|
33
32
|
|
|
34
33
|
@dataclass(slots=True, frozen=True)
|
|
@@ -46,7 +45,7 @@ class TagExpr(Expr):
|
|
|
46
45
|
out.append(f'"{self.tag}"')
|
|
47
46
|
|
|
48
47
|
@override
|
|
49
|
-
def render(self)
|
|
48
|
+
def render(self):
|
|
50
49
|
return self.tag
|
|
51
50
|
|
|
52
51
|
@override
|
|
@@ -9,7 +9,6 @@ from typing import final, override
|
|
|
9
9
|
from pulse.transpiler.nodes import Expr
|
|
10
10
|
from pulse.transpiler.py_module import PyModule
|
|
11
11
|
from pulse.transpiler.transpiler import Transpiler
|
|
12
|
-
from pulse.transpiler.vdom import VDOMNode
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
@dataclass(slots=True)
|
|
@@ -30,7 +29,7 @@ class TypeHint(Expr):
|
|
|
30
29
|
)
|
|
31
30
|
|
|
32
31
|
@override
|
|
33
|
-
def render(self)
|
|
32
|
+
def render(self):
|
|
34
33
|
raise TypeError(
|
|
35
34
|
f"Type hint '{self.name}' cannot be rendered. "
|
|
36
35
|
+ "It should only be used with typing.cast() or similar."
|
|
@@ -7,7 +7,7 @@ import warnings
|
|
|
7
7
|
from abc import ABC, abstractmethod
|
|
8
8
|
from collections.abc import Callable, Iterable, Sequence
|
|
9
9
|
from dataclasses import dataclass, field
|
|
10
|
-
from inspect import isfunction, signature
|
|
10
|
+
from inspect import currentframe, isfunction, signature
|
|
11
11
|
from typing import (
|
|
12
12
|
TYPE_CHECKING,
|
|
13
13
|
Any,
|
|
@@ -23,7 +23,7 @@ from typing import Literal as Lit
|
|
|
23
23
|
|
|
24
24
|
from pulse.env import env
|
|
25
25
|
from pulse.transpiler.errors import TranspileError
|
|
26
|
-
from pulse.transpiler.vdom import VDOMNode
|
|
26
|
+
from pulse.transpiler.vdom import VDOMExpr, VDOMNode, VDOMPrimitive
|
|
27
27
|
|
|
28
28
|
if TYPE_CHECKING:
|
|
29
29
|
from pulse.transpiler.transpiler import Transpiler
|
|
@@ -132,7 +132,7 @@ class Expr(ABC):
|
|
|
132
132
|
# -------------------------------------------------------------------------
|
|
133
133
|
|
|
134
134
|
@abstractmethod
|
|
135
|
-
def render(self) ->
|
|
135
|
+
def render(self) -> VDOMPrimitive | VDOMExpr:
|
|
136
136
|
"""Serialize this expression node for client-side rendering.
|
|
137
137
|
|
|
138
138
|
Returns a VDOMNode (primitive or dict) that can be JSON-serialized and
|
|
@@ -334,7 +334,7 @@ class ExprWrapper(Expr):
|
|
|
334
334
|
self.expr.emit(out)
|
|
335
335
|
|
|
336
336
|
@override
|
|
337
|
-
def render(self) ->
|
|
337
|
+
def render(self) -> VDOMPrimitive | VDOMExpr:
|
|
338
338
|
return self.expr.render()
|
|
339
339
|
|
|
340
340
|
@override
|
|
@@ -500,7 +500,7 @@ class Value(Expr):
|
|
|
500
500
|
_emit_value(self.value, out)
|
|
501
501
|
|
|
502
502
|
@override
|
|
503
|
-
def render(self) ->
|
|
503
|
+
def render(self) -> VDOMExpr:
|
|
504
504
|
raise TypeError(
|
|
505
505
|
"Value cannot be rendered as VDOMExpr; unwrap with .value instead"
|
|
506
506
|
)
|
|
@@ -540,15 +540,13 @@ class Element(Expr):
|
|
|
540
540
|
self.children = None
|
|
541
541
|
else:
|
|
542
542
|
if isinstance(tag, str):
|
|
543
|
-
parent_name = tag[2:] if tag.startswith("$$") else tag
|
|
543
|
+
parent_name: str | Expr = tag[2:] if tag.startswith("$$") else tag
|
|
544
544
|
else:
|
|
545
|
-
|
|
546
|
-
tag.emit(tag_out)
|
|
547
|
-
parent_name = "".join(tag_out)
|
|
545
|
+
parent_name = tag
|
|
548
546
|
self.children = flatten_children(
|
|
549
547
|
children,
|
|
550
548
|
parent_name=parent_name,
|
|
551
|
-
warn_stacklevel=
|
|
549
|
+
warn_stacklevel=None,
|
|
552
550
|
)
|
|
553
551
|
self.key = key
|
|
554
552
|
|
|
@@ -733,7 +731,7 @@ class Element(Expr):
|
|
|
733
731
|
return result
|
|
734
732
|
|
|
735
733
|
@override
|
|
736
|
-
def render(self)
|
|
734
|
+
def render(self):
|
|
737
735
|
"""Element rendering is handled by Renderer.render_node(), not render().
|
|
738
736
|
|
|
739
737
|
This method validates render-time constraints and raises TypeError
|
|
@@ -787,7 +785,7 @@ class PulseNode:
|
|
|
787
785
|
flat = flatten_children(
|
|
788
786
|
children_arg,
|
|
789
787
|
parent_name=parent_name,
|
|
790
|
-
warn_stacklevel=
|
|
788
|
+
warn_stacklevel=None,
|
|
791
789
|
)
|
|
792
790
|
return PulseNode(
|
|
793
791
|
fn=self.fn,
|
|
@@ -804,8 +802,8 @@ class PulseNode:
|
|
|
804
802
|
def flatten_children(
|
|
805
803
|
children: Sequence[Node | Iterable[Node]],
|
|
806
804
|
*,
|
|
807
|
-
parent_name: str,
|
|
808
|
-
warn_stacklevel: int =
|
|
805
|
+
parent_name: str | Expr,
|
|
806
|
+
warn_stacklevel: int | None = None,
|
|
809
807
|
) -> list[Node]:
|
|
810
808
|
if env.pulse_env == "dev":
|
|
811
809
|
return _flatten_children_dev(
|
|
@@ -835,13 +833,14 @@ def _flatten_children_prod(children: Sequence[Node | Iterable[Node]]) -> list[No
|
|
|
835
833
|
def _flatten_children_dev(
|
|
836
834
|
children: Sequence[Node | Iterable[Node]],
|
|
837
835
|
*,
|
|
838
|
-
parent_name: str,
|
|
839
|
-
warn_stacklevel: int =
|
|
836
|
+
parent_name: str | Expr,
|
|
837
|
+
warn_stacklevel: int | None = None,
|
|
840
838
|
) -> list[Node]:
|
|
841
839
|
flat: list[Node] = []
|
|
842
840
|
seen_keys: set[str] = set()
|
|
843
841
|
|
|
844
842
|
def visit(item: Node | Iterable[Node]) -> None:
|
|
843
|
+
nonlocal warn_stacklevel
|
|
845
844
|
if isinstance(item, dict):
|
|
846
845
|
raise TypeError("Dict is not a valid child")
|
|
847
846
|
if isinstance(item, Iterable) and not isinstance(item, str):
|
|
@@ -853,6 +852,32 @@ def _flatten_children_dev(
|
|
|
853
852
|
missing_key = True
|
|
854
853
|
visit(sub) # type: ignore[arg-type]
|
|
855
854
|
if missing_key:
|
|
855
|
+
if warn_stacklevel is None:
|
|
856
|
+
stacklevel = 1
|
|
857
|
+
frame = currentframe()
|
|
858
|
+
if frame is not None:
|
|
859
|
+
frame = frame.f_back
|
|
860
|
+
internal_prefixes = (
|
|
861
|
+
"pulse",
|
|
862
|
+
"pulse_mantine",
|
|
863
|
+
"pulse_ag_grid",
|
|
864
|
+
"pulse_recharts",
|
|
865
|
+
"pulse_lucide",
|
|
866
|
+
"pulse_msal",
|
|
867
|
+
"pulse_aws",
|
|
868
|
+
)
|
|
869
|
+
while frame is not None:
|
|
870
|
+
module = frame.f_globals.get("__name__", "")
|
|
871
|
+
if module and not any(
|
|
872
|
+
module == prefix or module.startswith(f"{prefix}.")
|
|
873
|
+
for prefix in internal_prefixes
|
|
874
|
+
):
|
|
875
|
+
break
|
|
876
|
+
stacklevel += 1
|
|
877
|
+
frame = frame.f_back
|
|
878
|
+
if frame is not None:
|
|
879
|
+
stacklevel += 1
|
|
880
|
+
warn_stacklevel = stacklevel
|
|
856
881
|
clean_name = clean_element_name(parent_name)
|
|
857
882
|
warnings.warn(
|
|
858
883
|
(
|
|
@@ -888,7 +913,25 @@ def _flatten_children_dev(
|
|
|
888
913
|
return flat
|
|
889
914
|
|
|
890
915
|
|
|
891
|
-
def clean_element_name(parent_name: str) -> str:
|
|
916
|
+
def clean_element_name(parent_name: str | Expr) -> str:
|
|
917
|
+
def expr_name(expr: Expr) -> str:
|
|
918
|
+
while isinstance(expr, ExprWrapper):
|
|
919
|
+
expr = expr.expr
|
|
920
|
+
if isinstance(expr, Member):
|
|
921
|
+
base = expr_name(expr.obj)
|
|
922
|
+
return f"{base}.{expr.prop}" if base else expr.prop
|
|
923
|
+
if isinstance(expr, Identifier):
|
|
924
|
+
return expr.name
|
|
925
|
+
if expr.__class__.__name__ == "Import":
|
|
926
|
+
name = getattr(expr, "name", None)
|
|
927
|
+
if isinstance(name, str) and name:
|
|
928
|
+
return name
|
|
929
|
+
out: list[str] = []
|
|
930
|
+
expr.emit(out)
|
|
931
|
+
return "".join(out)
|
|
932
|
+
|
|
933
|
+
if isinstance(parent_name, Expr):
|
|
934
|
+
parent_name = expr_name(parent_name)
|
|
892
935
|
if parent_name.startswith("<") and parent_name.endswith(">"):
|
|
893
936
|
return parent_name
|
|
894
937
|
return f"<{parent_name}>"
|
|
@@ -916,7 +959,7 @@ class Identifier(Expr):
|
|
|
916
959
|
out.append(self.name)
|
|
917
960
|
|
|
918
961
|
@override
|
|
919
|
-
def render(self) ->
|
|
962
|
+
def render(self) -> VDOMExpr:
|
|
920
963
|
return {"t": "id", "name": self.name}
|
|
921
964
|
|
|
922
965
|
|
|
@@ -940,7 +983,7 @@ class Literal(Expr):
|
|
|
940
983
|
out.append(str(self.value))
|
|
941
984
|
|
|
942
985
|
@override
|
|
943
|
-
def render(self) ->
|
|
986
|
+
def render(self) -> VDOMPrimitive:
|
|
944
987
|
return self.value
|
|
945
988
|
|
|
946
989
|
|
|
@@ -958,7 +1001,7 @@ class Undefined(Expr):
|
|
|
958
1001
|
out.append("undefined")
|
|
959
1002
|
|
|
960
1003
|
@override
|
|
961
|
-
def render(self) ->
|
|
1004
|
+
def render(self) -> VDOMExpr:
|
|
962
1005
|
return {"t": "undef"}
|
|
963
1006
|
|
|
964
1007
|
|
|
@@ -982,7 +1025,7 @@ class Array(Expr):
|
|
|
982
1025
|
out.append("]")
|
|
983
1026
|
|
|
984
1027
|
@override
|
|
985
|
-
def render(self) ->
|
|
1028
|
+
def render(self) -> VDOMExpr:
|
|
986
1029
|
return {"t": "array", "items": [e.render() for e in self.elements]}
|
|
987
1030
|
|
|
988
1031
|
|
|
@@ -1014,7 +1057,7 @@ class Object(Expr):
|
|
|
1014
1057
|
out.append("}")
|
|
1015
1058
|
|
|
1016
1059
|
@override
|
|
1017
|
-
def render(self) ->
|
|
1060
|
+
def render(self) -> VDOMExpr:
|
|
1018
1061
|
rendered_props: dict[str, VDOMNode] = {}
|
|
1019
1062
|
for prop in self.props:
|
|
1020
1063
|
if isinstance(prop, Spread):
|
|
@@ -1038,7 +1081,7 @@ class Member(Expr):
|
|
|
1038
1081
|
out.append(self.prop)
|
|
1039
1082
|
|
|
1040
1083
|
@override
|
|
1041
|
-
def render(self) ->
|
|
1084
|
+
def render(self) -> VDOMExpr:
|
|
1042
1085
|
return {"t": "member", "obj": self.obj.render(), "prop": self.prop}
|
|
1043
1086
|
|
|
1044
1087
|
|
|
@@ -1057,7 +1100,7 @@ class Subscript(Expr):
|
|
|
1057
1100
|
out.append("]")
|
|
1058
1101
|
|
|
1059
1102
|
@override
|
|
1060
|
-
def render(self) ->
|
|
1103
|
+
def render(self) -> VDOMExpr:
|
|
1061
1104
|
return {"t": "sub", "obj": self.obj.render(), "key": self.key.render()}
|
|
1062
1105
|
|
|
1063
1106
|
|
|
@@ -1079,7 +1122,7 @@ class Call(Expr):
|
|
|
1079
1122
|
out.append(")")
|
|
1080
1123
|
|
|
1081
1124
|
@override
|
|
1082
|
-
def render(self) ->
|
|
1125
|
+
def render(self) -> VDOMExpr:
|
|
1083
1126
|
return {
|
|
1084
1127
|
"t": "call",
|
|
1085
1128
|
"callee": self.callee.render(),
|
|
@@ -1110,7 +1153,7 @@ class Unary(Expr):
|
|
|
1110
1153
|
_emit_paren(self.operand, self.op, "unary", out)
|
|
1111
1154
|
|
|
1112
1155
|
@override
|
|
1113
|
-
def render(self) ->
|
|
1156
|
+
def render(self) -> VDOMExpr:
|
|
1114
1157
|
if self.op == "await":
|
|
1115
1158
|
raise TypeError("await is not supported in VDOM expressions")
|
|
1116
1159
|
return {"t": "unary", "op": self.op, "arg": self.operand.render()}
|
|
@@ -1148,7 +1191,7 @@ class Binary(Expr):
|
|
|
1148
1191
|
_emit_paren(self.right, self.op, "right", out)
|
|
1149
1192
|
|
|
1150
1193
|
@override
|
|
1151
|
-
def render(self) ->
|
|
1194
|
+
def render(self) -> VDOMExpr:
|
|
1152
1195
|
return {
|
|
1153
1196
|
"t": "binary",
|
|
1154
1197
|
"op": self.op,
|
|
@@ -1178,7 +1221,7 @@ class Ternary(Expr):
|
|
|
1178
1221
|
self.else_.emit(out)
|
|
1179
1222
|
|
|
1180
1223
|
@override
|
|
1181
|
-
def render(self) ->
|
|
1224
|
+
def render(self) -> VDOMExpr:
|
|
1182
1225
|
return {
|
|
1183
1226
|
"t": "ternary",
|
|
1184
1227
|
"cond": self.cond.render(),
|
|
@@ -1224,7 +1267,7 @@ class Arrow(Expr):
|
|
|
1224
1267
|
out.append("}")
|
|
1225
1268
|
|
|
1226
1269
|
@override
|
|
1227
|
-
def render(self) ->
|
|
1270
|
+
def render(self) -> VDOMExpr:
|
|
1228
1271
|
if not isinstance(self.body, Expr):
|
|
1229
1272
|
raise TypeError("Arrow with statement body cannot be rendered as VDOMExpr")
|
|
1230
1273
|
return {"t": "arrow", "params": list(self.params), "body": self.body.render()}
|
|
@@ -1253,7 +1296,7 @@ class Template(Expr):
|
|
|
1253
1296
|
out.append("`")
|
|
1254
1297
|
|
|
1255
1298
|
@override
|
|
1256
|
-
def render(self) ->
|
|
1299
|
+
def render(self) -> VDOMExpr:
|
|
1257
1300
|
rendered_parts: list[str | VDOMNode] = []
|
|
1258
1301
|
for p in self.parts:
|
|
1259
1302
|
if isinstance(p, str):
|
|
@@ -1275,7 +1318,7 @@ class Spread(Expr):
|
|
|
1275
1318
|
self.expr.emit(out)
|
|
1276
1319
|
|
|
1277
1320
|
@override
|
|
1278
|
-
def render(self) ->
|
|
1321
|
+
def render(self) -> VDOMExpr:
|
|
1279
1322
|
raise TypeError("Spread cannot be rendered as VDOMExpr directly")
|
|
1280
1323
|
|
|
1281
1324
|
|
|
@@ -1313,7 +1356,7 @@ class New(Expr):
|
|
|
1313
1356
|
out.append(")")
|
|
1314
1357
|
|
|
1315
1358
|
@override
|
|
1316
|
-
def render(self) ->
|
|
1359
|
+
def render(self) -> VDOMExpr:
|
|
1317
1360
|
return {
|
|
1318
1361
|
"t": "new",
|
|
1319
1362
|
"ctor": self.ctor.render(),
|
|
@@ -1377,7 +1420,7 @@ class Transformer(Expr, Generic[_F]):
|
|
|
1377
1420
|
raise TypeError(f"{label} cannot be subscripted")
|
|
1378
1421
|
|
|
1379
1422
|
@override
|
|
1380
|
-
def render(self) ->
|
|
1423
|
+
def render(self) -> VDOMExpr:
|
|
1381
1424
|
label = self.name or "Transformer"
|
|
1382
1425
|
raise TypeError(f"{label} cannot be rendered - must be called")
|
|
1383
1426
|
|
|
@@ -1677,7 +1720,7 @@ class Function(Expr):
|
|
|
1677
1720
|
out.append("}")
|
|
1678
1721
|
|
|
1679
1722
|
@override
|
|
1680
|
-
def render(self) ->
|
|
1723
|
+
def render(self) -> VDOMExpr:
|
|
1681
1724
|
raise TypeError("Function cannot be rendered as VDOMExpr")
|
|
1682
1725
|
|
|
1683
1726
|
|
|
@@ -11,7 +11,6 @@ from types import ModuleType
|
|
|
11
11
|
from typing import TYPE_CHECKING, Any, ClassVar, cast, override
|
|
12
12
|
|
|
13
13
|
from pulse.transpiler.nodes import Expr, Primitive, Transformer
|
|
14
|
-
from pulse.transpiler.vdom import VDOMNode
|
|
15
14
|
|
|
16
15
|
if TYPE_CHECKING:
|
|
17
16
|
from pulse.transpiler.transpiler import Transpiler
|
|
@@ -62,7 +61,7 @@ class PyModule(Expr):
|
|
|
62
61
|
raise TypeError(f"{label} cannot be emitted directly")
|
|
63
62
|
|
|
64
63
|
@override
|
|
65
|
-
def render(self)
|
|
64
|
+
def render(self):
|
|
66
65
|
label = self.name or "PyModule"
|
|
67
66
|
raise TypeError(f"{label} cannot be rendered directly")
|
|
68
67
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pulse_framework-0.1.61 → pulse_framework-0.1.63}/src/pulse/transpiler/modules/pulse/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|