jac-client 0.2.0__py3-none-any.whl → 0.2.3__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.
- jac_client/docs/README.md +50 -20
- jac_client/docs/advanced-state.md +13 -14
- jac_client/docs/asset-serving/intro.md +209 -0
- jac_client/docs/assets/pipe_line-v2.svg +32 -0
- jac_client/docs/file-system/app.jac.md +121 -0
- jac_client/docs/file-system/backend-frontend.md +217 -0
- jac_client/docs/file-system/intro.md +72 -0
- jac_client/docs/file-system/nested-imports.md +348 -0
- jac_client/docs/guide-example/intro.md +11 -13
- jac_client/docs/guide-example/step-01-setup.md +30 -20
- jac_client/docs/guide-example/step-02-components.md +24 -24
- jac_client/docs/guide-example/step-03-styling.md +24 -24
- jac_client/docs/guide-example/step-04-todo-ui.md +17 -17
- jac_client/docs/guide-example/step-05-local-state.md +23 -23
- jac_client/docs/guide-example/step-06-events.md +23 -24
- jac_client/docs/guide-example/step-07-effects.md +27 -28
- jac_client/docs/guide-example/step-08-walkers.md +23 -23
- jac_client/docs/guide-example/step-09-authentication.md +18 -18
- jac_client/docs/guide-example/step-10-routing.md +20 -21
- jac_client/docs/guide-example/step-11-final.md +34 -35
- jac_client/docs/imports.md +4 -5
- jac_client/docs/lifecycle-hooks.md +12 -13
- jac_client/docs/routing.md +21 -22
- jac_client/docs/styling/intro.md +249 -0
- jac_client/docs/styling/js-styling.md +367 -0
- jac_client/docs/styling/material-ui.md +341 -0
- jac_client/docs/styling/pure-css.md +299 -0
- jac_client/docs/styling/sass.md +403 -0
- jac_client/docs/styling/styled-components.md +395 -0
- jac_client/docs/styling/tailwind.md +298 -0
- jac_client/examples/all-in-one/.babelrc +9 -0
- jac_client/examples/all-in-one/README.md +16 -0
- jac_client/examples/all-in-one/app.jac +426 -0
- jac_client/examples/all-in-one/assets/burger.png +0 -0
- jac_client/examples/all-in-one/button.jac +7 -0
- jac_client/examples/all-in-one/components/button.jac +7 -0
- jac_client/examples/all-in-one/package.json +29 -0
- jac_client/examples/all-in-one/styles.css +26 -0
- jac_client/examples/all-in-one/vite.config.js +28 -0
- jac_client/examples/asset-serving/css-with-image/.babelrc +9 -0
- jac_client/examples/asset-serving/css-with-image/README.md +91 -0
- jac_client/examples/asset-serving/css-with-image/app.jac +88 -0
- jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
- jac_client/examples/asset-serving/css-with-image/package.json +28 -0
- jac_client/examples/asset-serving/css-with-image/styles.css +26 -0
- jac_client/examples/asset-serving/css-with-image/vite.config.js +28 -0
- jac_client/examples/asset-serving/image-asset/.babelrc +9 -0
- jac_client/examples/asset-serving/image-asset/README.md +119 -0
- jac_client/examples/asset-serving/image-asset/app.jac +55 -0
- jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
- jac_client/examples/asset-serving/image-asset/package.json +28 -0
- jac_client/examples/asset-serving/image-asset/styles.css +26 -0
- jac_client/examples/asset-serving/image-asset/vite.config.js +28 -0
- jac_client/examples/asset-serving/import-alias/.babelrc +9 -0
- jac_client/examples/asset-serving/import-alias/README.md +83 -0
- jac_client/examples/asset-serving/import-alias/app.jac +111 -0
- jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
- jac_client/examples/asset-serving/import-alias/package.json +28 -0
- jac_client/examples/asset-serving/import-alias/vite.config.js +28 -0
- jac_client/examples/basic/app.jac +14 -9
- jac_client/examples/basic/package.json +1 -1
- jac_client/examples/basic/vite.config.js +0 -1
- jac_client/examples/basic-auth/package.json +1 -1
- jac_client/examples/basic-auth/vite.config.js +0 -1
- jac_client/examples/basic-auth-with-router/package.json +1 -1
- jac_client/examples/basic-auth-with-router/vite.config.js +0 -1
- jac_client/examples/basic-full-stack/package.json +1 -1
- jac_client/examples/basic-full-stack/vite.config.js +0 -1
- jac_client/examples/css-styling/js-styling/.babelrc +9 -0
- jac_client/examples/css-styling/js-styling/README.md +183 -0
- jac_client/examples/css-styling/js-styling/app.jac +84 -0
- jac_client/examples/css-styling/js-styling/package.json +28 -0
- jac_client/examples/css-styling/js-styling/styles.js +100 -0
- jac_client/examples/css-styling/js-styling/vite.config.js +27 -0
- jac_client/examples/css-styling/material-ui/.babelrc +9 -0
- jac_client/examples/css-styling/material-ui/README.md +16 -0
- jac_client/examples/css-styling/material-ui/app.jac +122 -0
- jac_client/examples/css-styling/material-ui/package.json +32 -0
- jac_client/examples/css-styling/material-ui/vite.config.js +27 -0
- jac_client/examples/css-styling/pure-css/.babelrc +9 -0
- jac_client/examples/css-styling/pure-css/README.md +16 -0
- jac_client/examples/css-styling/pure-css/app.jac +64 -0
- jac_client/examples/css-styling/pure-css/package.json +28 -0
- jac_client/examples/css-styling/pure-css/styles.css +111 -0
- jac_client/examples/css-styling/pure-css/vite.config.js +27 -0
- jac_client/examples/css-styling/sass-example/.babelrc +9 -0
- jac_client/examples/css-styling/sass-example/README.md +16 -0
- jac_client/examples/css-styling/sass-example/app.jac +64 -0
- jac_client/examples/css-styling/sass-example/package.json +29 -0
- jac_client/examples/css-styling/sass-example/styles.scss +153 -0
- jac_client/examples/css-styling/sass-example/vite.config.js +27 -0
- jac_client/examples/css-styling/styled-components/.babelrc +9 -0
- jac_client/examples/css-styling/styled-components/README.md +16 -0
- jac_client/examples/css-styling/styled-components/app.jac +71 -0
- jac_client/examples/css-styling/styled-components/package.json +29 -0
- jac_client/examples/css-styling/styled-components/styled.js +90 -0
- jac_client/examples/css-styling/styled-components/vite.config.js +27 -0
- jac_client/examples/css-styling/tailwind-example/.babelrc +9 -0
- jac_client/examples/css-styling/tailwind-example/README.md +16 -0
- jac_client/examples/css-styling/tailwind-example/app.jac +63 -0
- jac_client/examples/css-styling/tailwind-example/global.css +1 -0
- jac_client/examples/css-styling/tailwind-example/package.json +30 -0
- jac_client/examples/css-styling/tailwind-example/vite.config.js +29 -0
- jac_client/examples/full-stack-with-auth/app.jac +20 -33
- jac_client/examples/full-stack-with-auth/package.json +1 -1
- jac_client/examples/full-stack-with-auth/vite.config.js +0 -1
- jac_client/examples/little-x/app.jac +327 -218
- jac_client/examples/little-x/submit-button.jac +1 -1
- jac_client/examples/nested-folders/nested-advance/.babelrc +9 -0
- jac_client/examples/nested-folders/nested-advance/ButtonRoot.jac +11 -0
- jac_client/examples/nested-folders/nested-advance/README.md +77 -0
- jac_client/examples/nested-folders/nested-advance/app.jac +35 -0
- jac_client/examples/nested-folders/nested-advance/level1/ButtonSecondL.jac +19 -0
- jac_client/examples/nested-folders/nested-advance/level1/Card.jac +43 -0
- jac_client/examples/nested-folders/nested-advance/level1/level2/ButtonThirdL.jac +25 -0
- jac_client/examples/nested-folders/nested-advance/package.json +29 -0
- jac_client/examples/nested-folders/nested-advance/vite.config.js +28 -0
- jac_client/examples/nested-folders/nested-basic/.babelrc +9 -0
- jac_client/examples/nested-folders/nested-basic/README.md +183 -0
- jac_client/examples/nested-folders/nested-basic/app.jac +13 -0
- jac_client/examples/nested-folders/nested-basic/app.js +7 -0
- jac_client/examples/nested-folders/nested-basic/button.jac +7 -0
- jac_client/examples/nested-folders/nested-basic/components/button.jac +7 -0
- jac_client/examples/nested-folders/nested-basic/package.json +28 -0
- jac_client/examples/nested-folders/nested-basic/vite.config.js +27 -0
- jac_client/examples/with-router/app.jac +1 -1
- jac_client/examples/with-router/package.json +1 -1
- jac_client/examples/with-router/vite.config.js +0 -1
- jac_client/plugin/cli.py +7 -2
- jac_client/plugin/client.py +68 -5
- jac_client/plugin/client_runtime.jac +1 -1
- jac_client/plugin/vite_client_bundle.py +162 -14
- jac_client/tests/__init__.py +0 -1
- jac_client/tests/fixtures/basic-app/app.jac +7 -2
- jac_client/tests/fixtures/cl_file/app.cl.jac +48 -0
- jac_client/tests/fixtures/cl_file/app.jac +15 -0
- jac_client/tests/fixtures/client_app_with_antd/app.jac +14 -8
- jac_client/tests/fixtures/js_import/app.jac +19 -15
- jac_client/tests/fixtures/js_import/utils.js +0 -1
- jac_client/tests/fixtures/package.json +1 -1
- jac_client/tests/fixtures/relative_import/app.jac +4 -6
- jac_client/tests/fixtures/relative_import/button.jac +7 -6
- jac_client/tests/fixtures/spawn_test/app.jac +1 -5
- jac_client/tests/fixtures/test_fragments_spread/app.jac +24 -10
- jac_client/tests/test_asset_examples.py +322 -0
- jac_client/tests/test_cl.py +480 -426
- jac_client/tests/test_create_jac_app.py +125 -133
- jac_client/tests/test_it.py +329 -0
- jac_client/tests/test_nested_file.py +374 -0
- {jac_client-0.2.0.dist-info → jac_client-0.2.3.dist-info}/METADATA +11 -3
- jac_client-0.2.3.dist-info/RECORD +171 -0
- jac_client-0.2.0.dist-info/RECORD +0 -72
- {jac_client-0.2.0.dist-info → jac_client-0.2.3.dist-info}/WHEEL +0 -0
- {jac_client-0.2.0.dist-info → jac_client-0.2.3.dist-info}/entry_points.txt +0 -0
jac_client/tests/test_cl.py
CHANGED
|
@@ -2,73 +2,74 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from pathlib import Path
|
|
6
5
|
import json
|
|
7
|
-
import tempfile
|
|
8
6
|
import subprocess
|
|
7
|
+
import tempfile
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
9
11
|
|
|
10
|
-
from jaclang.runtimelib.machine import JacMachine as Jac
|
|
11
|
-
from jaclang.utils.test import TestCase
|
|
12
12
|
from jac_client.plugin.vite_client_bundle import ViteClientBundleBuilder
|
|
13
|
+
from jaclang.runtimelib.runtime import JacRuntime as Jac
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
16
|
+
@pytest.fixture(autouse=True)
|
|
17
|
+
def reset_jac_machine():
|
|
18
|
+
"""Reset Jac machine before and after each test."""
|
|
19
|
+
Jac.reset_machine()
|
|
20
|
+
yield
|
|
21
|
+
Jac.reset_machine()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _create_test_project_with_vite(
|
|
25
|
+
temp_path: Path, include_antd: bool = False
|
|
26
|
+
) -> tuple[Path, Path]:
|
|
27
|
+
"""Create a minimal test project with Vite installed.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
temp_path: Path to the temporary directory
|
|
31
|
+
include_antd: If True, includes antd in dependencies
|
|
32
|
+
"""
|
|
33
|
+
# Create package.json with base dependencies
|
|
34
|
+
dependencies = {
|
|
35
|
+
"react": "^19.2.0",
|
|
36
|
+
"react-dom": "^19.2.0",
|
|
37
|
+
"react-router-dom": "^7.3.0",
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Add antd if requested
|
|
41
|
+
if include_antd:
|
|
42
|
+
dependencies["antd"] = "^5.0.0"
|
|
43
|
+
|
|
44
|
+
# Create package.json structure
|
|
45
|
+
package_data = {
|
|
46
|
+
"name": "test-client",
|
|
47
|
+
"version": "0.0.1",
|
|
48
|
+
"type": "module",
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "npm run compile && vite build",
|
|
51
|
+
"dev": "vite dev",
|
|
52
|
+
"preview": "vite preview",
|
|
53
|
+
"compile": 'babel src --out-dir build --extensions ".jsx,.js" --out-file-extension .js',
|
|
54
|
+
},
|
|
55
|
+
"dependencies": dependencies,
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"vite": "^6.4.1",
|
|
58
|
+
"@babel/cli": "^7.28.3",
|
|
59
|
+
"@babel/core": "^7.28.5",
|
|
60
|
+
"@babel/preset-env": "^7.28.5",
|
|
61
|
+
"@babel/preset-react": "^7.28.5",
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
package_json = temp_path / "package.json"
|
|
66
|
+
with package_json.open("w", encoding="utf-8") as f:
|
|
67
|
+
json.dump(package_data, f, indent=2)
|
|
68
|
+
|
|
69
|
+
# Create .babelrc file
|
|
70
|
+
babelrc = temp_path / ".babelrc"
|
|
71
|
+
babelrc.write_text(
|
|
72
|
+
"""{
|
|
72
73
|
"presets": [[
|
|
73
74
|
"@babel/preset-env",
|
|
74
75
|
{
|
|
@@ -76,11 +77,14 @@ class ViteClientBundleBuilderTests(TestCase):
|
|
|
76
77
|
}
|
|
77
78
|
], "@babel/preset-react"]
|
|
78
79
|
}
|
|
79
|
-
""",
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
""",
|
|
81
|
+
encoding="utf-8",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Create vite.config.js file
|
|
85
|
+
vite_config = temp_path / "vite.config.js"
|
|
86
|
+
vite_config.write_text(
|
|
87
|
+
"""import { defineConfig } from "vite";
|
|
84
88
|
import path from "path";
|
|
85
89
|
import { fileURLToPath } from "url";
|
|
86
90
|
|
|
@@ -107,370 +111,420 @@ export default defineConfig({
|
|
|
107
111
|
},
|
|
108
112
|
},
|
|
109
113
|
});
|
|
110
|
-
""",
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
""",
|
|
115
|
+
encoding="utf-8",
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# Install dependencies
|
|
119
|
+
result = subprocess.run(
|
|
120
|
+
["npm", "install"],
|
|
121
|
+
cwd=temp_path,
|
|
122
|
+
check=False,
|
|
123
|
+
capture_output=True,
|
|
124
|
+
text=True,
|
|
125
|
+
)
|
|
126
|
+
if result.returncode != 0:
|
|
127
|
+
error_msg = f"npm install failed with exit code {result.returncode}\n"
|
|
128
|
+
error_msg += f"stdout: {result.stdout}\n"
|
|
129
|
+
error_msg += f"stderr: {result.stderr}\n"
|
|
130
|
+
raise RuntimeError(error_msg)
|
|
131
|
+
|
|
132
|
+
# Create output directory
|
|
133
|
+
output_dir = temp_path / "dist"
|
|
134
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
135
|
+
|
|
136
|
+
src_dir = temp_path / "src"
|
|
137
|
+
src_dir.mkdir(parents=True, exist_ok=True)
|
|
138
|
+
|
|
139
|
+
build_dir = temp_path / "build"
|
|
140
|
+
build_dir.mkdir(parents=True, exist_ok=True)
|
|
141
|
+
|
|
142
|
+
return package_json, output_dir
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def test_build_bundle_with_vite() -> None:
|
|
146
|
+
"""Test that Vite bundling produces optimized output with proper structure."""
|
|
147
|
+
# Create a temporary directory for our test project
|
|
148
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
149
|
+
temp_path = Path(temp_dir)
|
|
150
|
+
|
|
151
|
+
package_json, output_dir = _create_test_project_with_vite(temp_path)
|
|
152
|
+
runtime_path = Path(__file__).parent.parent / "plugin" / "client_runtime.jac"
|
|
153
|
+
# Initialize the Vite builder
|
|
154
|
+
builder = ViteClientBundleBuilder(
|
|
155
|
+
runtime_path=runtime_path,
|
|
156
|
+
vite_package_json=package_json,
|
|
157
|
+
vite_output_dir=output_dir,
|
|
158
|
+
vite_minify=False, # Disable minification for easier inspection
|
|
119
159
|
)
|
|
120
|
-
|
|
121
|
-
error_msg = f"npm install failed with exit code {result.returncode}\n"
|
|
122
|
-
error_msg += f"stdout: {result.stdout}\n"
|
|
123
|
-
error_msg += f"stderr: {result.stderr}\n"
|
|
124
|
-
raise RuntimeError(error_msg)
|
|
125
|
-
|
|
126
|
-
# Create output directory
|
|
127
|
-
output_dir = temp_path / "dist"
|
|
128
|
-
output_dir.mkdir(parents=True, exist_ok=True)
|
|
129
|
-
|
|
130
|
-
src_dir = temp_path / "src"
|
|
131
|
-
src_dir.mkdir(parents=True, exist_ok=True)
|
|
132
|
-
|
|
133
|
-
build_dir = temp_path / "build"
|
|
134
|
-
build_dir.mkdir(parents=True, exist_ok=True)
|
|
135
|
-
|
|
136
|
-
return package_json, output_dir
|
|
137
|
-
|
|
138
|
-
def test_build_bundle_with_vite(self) -> None:
|
|
139
|
-
"""Test that Vite bundling produces optimized output with proper structure."""
|
|
140
|
-
# Create a temporary directory for our test project
|
|
141
|
-
with tempfile.TemporaryDirectory() as temp_dir:
|
|
142
|
-
temp_path = Path(temp_dir)
|
|
143
|
-
|
|
144
|
-
package_json, output_dir = self._create_test_project_with_vite(temp_path)
|
|
145
|
-
runtime_path = Path(__file__).parent.parent / "plugin" / "client_runtime.jac"
|
|
146
|
-
# Initialize the Vite builder
|
|
147
|
-
builder = ViteClientBundleBuilder(
|
|
148
|
-
runtime_path=runtime_path,
|
|
149
|
-
vite_package_json=package_json,
|
|
150
|
-
vite_output_dir=output_dir,
|
|
151
|
-
vite_minify=False, # Disable minification for easier inspection
|
|
152
|
-
)
|
|
153
|
-
# Import the test module
|
|
154
|
-
fixtures_dir = Path(__file__).parent / "fixtures" / "basic-app"
|
|
155
|
-
(module,) = Jac.jac_import("app", str(fixtures_dir))
|
|
156
|
-
# Build the bundle
|
|
157
|
-
bundle = builder.build(module, force=True)
|
|
158
|
-
|
|
159
|
-
self.assertIsNotNone(bundle)
|
|
160
|
-
self.assertEqual(bundle.module_name, "app")
|
|
161
|
-
self.assertIn("app", bundle.client_functions)
|
|
162
|
-
self.assertIn("ButtonProps", bundle.client_functions)
|
|
163
|
-
self.assertIn("API_LABEL", bundle.client_globals)
|
|
164
|
-
self.assertGreater(len(bundle.hash), 10)
|
|
165
|
-
|
|
166
|
-
# Verify bundle code contains expected content
|
|
167
|
-
self.assertIn("function app()", bundle.code)
|
|
168
|
-
self.assertIn('API_LABEL = "Runtime Test";', bundle.code)
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
# Verify bundle was written to output directory
|
|
172
|
-
bundle_files = list(output_dir.glob("client.*.js"))
|
|
173
|
-
self.assertGreater(len(bundle_files), 0, "Expected at least one bundle file")
|
|
174
|
-
|
|
175
|
-
# Verify cached bundle is identical
|
|
176
|
-
cached = builder.build(module, force=False)
|
|
177
|
-
self.assertEqual(bundle.hash, cached.hash)
|
|
178
|
-
self.assertEqual(bundle.code, cached.code)
|
|
179
|
-
|
|
180
|
-
def test_vite_bundle_without_package_json(self) -> None:
|
|
181
|
-
"""Test that missing package.json raises appropriate error."""
|
|
160
|
+
# Import the test module
|
|
182
161
|
fixtures_dir = Path(__file__).parent / "fixtures" / "basic-app"
|
|
183
162
|
(module,) = Jac.jac_import("app", str(fixtures_dir))
|
|
184
|
-
|
|
163
|
+
# Build the bundle
|
|
164
|
+
bundle = builder.build(module, force=True)
|
|
165
|
+
|
|
166
|
+
assert bundle is not None
|
|
167
|
+
assert bundle.module_name == "app"
|
|
168
|
+
assert "app" in bundle.client_functions
|
|
169
|
+
assert "ButtonProps" in bundle.client_functions
|
|
170
|
+
assert "API_LABEL" in bundle.client_globals
|
|
171
|
+
assert len(bundle.hash) > 10
|
|
172
|
+
|
|
173
|
+
# Verify bundle code contains expected content
|
|
174
|
+
assert "function app()" in bundle.code
|
|
175
|
+
assert 'API_LABEL = "Runtime Test";' in bundle.code
|
|
176
|
+
|
|
177
|
+
# Verify bundle was written to output directory
|
|
178
|
+
bundle_files = list(output_dir.glob("client.*.js"))
|
|
179
|
+
assert len(bundle_files) > 0, "Expected at least one bundle file"
|
|
180
|
+
|
|
181
|
+
# Verify cached bundle is identical
|
|
182
|
+
cached = builder.build(module, force=False)
|
|
183
|
+
assert bundle.hash == cached.hash
|
|
184
|
+
assert bundle.code == cached.code
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def test_vite_bundle_without_package_json() -> None:
|
|
188
|
+
"""Test that missing package.json raises appropriate error."""
|
|
189
|
+
fixtures_dir = Path(__file__).parent / "fixtures" / "basic-app"
|
|
190
|
+
(module,) = Jac.jac_import("app", str(fixtures_dir))
|
|
191
|
+
|
|
192
|
+
runtime_path = Path(__file__).parent.parent / "plugin" / "client_runtime.jac"
|
|
193
|
+
|
|
194
|
+
# Create builder without package.json
|
|
195
|
+
builder = ViteClientBundleBuilder(
|
|
196
|
+
runtime_path=runtime_path,
|
|
197
|
+
vite_package_json=Path("/nonexistent/package.json"),
|
|
198
|
+
vite_output_dir=Path("/tmp/output"),
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
# Building should raise an error
|
|
202
|
+
from jaclang.runtimelib.client_bundle import ClientBundleError
|
|
203
|
+
|
|
204
|
+
with pytest.raises(ClientBundleError) as cm:
|
|
205
|
+
builder.build(module, force=True)
|
|
206
|
+
|
|
207
|
+
assert "Vite package.json not found" in str(cm.value)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def test_build_bundle_with_antd() -> None:
|
|
211
|
+
"""Test that Vite bundling works with Ant Design components."""
|
|
212
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
213
|
+
temp_path = Path(temp_dir)
|
|
214
|
+
|
|
215
|
+
# Create project with Vite and Ant Design installed
|
|
216
|
+
package_json, output_dir = _create_test_project_with_vite(
|
|
217
|
+
temp_path, include_antd=True
|
|
218
|
+
)
|
|
219
|
+
runtime_path = Path(__file__).parent.parent / "plugin" / "client_runtime.jac"
|
|
220
|
+
|
|
221
|
+
# Initialize the Vite builder
|
|
222
|
+
builder = ViteClientBundleBuilder(
|
|
223
|
+
runtime_path=runtime_path,
|
|
224
|
+
vite_package_json=package_json,
|
|
225
|
+
vite_output_dir=output_dir,
|
|
226
|
+
vite_minify=False,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
# Import the test module with Ant Design
|
|
230
|
+
fixtures_dir = Path(__file__).parent / "fixtures" / "client_app_with_antd"
|
|
231
|
+
(module,) = Jac.jac_import("app", str(fixtures_dir))
|
|
232
|
+
|
|
233
|
+
# Build the bundle
|
|
234
|
+
bundle = builder.build(module, force=True)
|
|
235
|
+
|
|
236
|
+
# Verify bundle structure
|
|
237
|
+
assert bundle is not None
|
|
238
|
+
assert bundle.module_name == "app"
|
|
239
|
+
assert "ButtonTest" in bundle.client_functions
|
|
240
|
+
assert "CardTest" in bundle.client_functions
|
|
241
|
+
assert "APP_NAME" in bundle.client_globals
|
|
242
|
+
|
|
243
|
+
# Verify bundle code contains expected content
|
|
244
|
+
assert "function ButtonTest()" in bundle.code
|
|
245
|
+
assert "function CardTest()" in bundle.code
|
|
246
|
+
assert 'APP_NAME = "Ant Design Test";' in bundle.code
|
|
247
|
+
|
|
248
|
+
# verify antd components are present
|
|
249
|
+
assert "ButtonGroup" in bundle.code
|
|
250
|
+
|
|
251
|
+
# Verify the Ant Design fixture content is present
|
|
252
|
+
assert "Testing Ant Design integration" in bundle.code
|
|
253
|
+
|
|
254
|
+
# Verify bundle was written to output directory
|
|
255
|
+
bundle_files = list(output_dir.glob("client.*.js"))
|
|
256
|
+
assert len(bundle_files) > 0, "Expected at least one bundle file"
|
|
257
|
+
|
|
258
|
+
# Cleanup
|
|
259
|
+
builder.cleanup_temp_dir()
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def test_relative_import() -> None:
|
|
263
|
+
"""Test that relative imports work correctly in Vite bundling."""
|
|
264
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
265
|
+
temp_path = Path(temp_dir)
|
|
266
|
+
|
|
267
|
+
# Create project with Vite installed
|
|
268
|
+
package_json, output_dir = _create_test_project_with_vite(
|
|
269
|
+
temp_path, include_antd=True
|
|
270
|
+
)
|
|
185
271
|
runtime_path = Path(__file__).parent.parent / "plugin" / "client_runtime.jac"
|
|
186
|
-
|
|
187
|
-
#
|
|
272
|
+
|
|
273
|
+
# Initialize the Vite builder
|
|
188
274
|
builder = ViteClientBundleBuilder(
|
|
189
275
|
runtime_path=runtime_path,
|
|
190
|
-
vite_package_json=
|
|
191
|
-
vite_output_dir=
|
|
276
|
+
vite_package_json=package_json,
|
|
277
|
+
vite_output_dir=output_dir,
|
|
278
|
+
vite_minify=False,
|
|
192
279
|
)
|
|
193
|
-
|
|
194
|
-
#
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
(
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
""
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
self.assertIn('"550e8400-e29b-41d4-a716-446655440000"', bundle.code)
|
|
445
|
-
|
|
446
|
-
# Reverse UUID spawn: parameterized_walker(value=100) spawn another_node_id
|
|
447
|
-
# Should generate: __jacSpawn("parameterized_walker", another_node_id, {value: 100})
|
|
448
|
-
self.assertRegex(
|
|
449
|
-
bundle.code,
|
|
450
|
-
r'__jacSpawn\("parameterized_walker",\s*another_node_id,\s*\{[^}]*"value":\s*100[^}]*\}\)'
|
|
451
|
-
)
|
|
452
|
-
self.assertIn('"6ba7b810-9dad-11d1-80b4-00c04fd430c8"', bundle.code)
|
|
453
|
-
|
|
454
|
-
# Verify positional argument mapping for walkers
|
|
455
|
-
self.assertRegex(
|
|
456
|
-
bundle.code,
|
|
457
|
-
r'__jacSpawn\("positional_walker",\s*node_id,\s*\{[^}]*"label":\s*"Node positional"[^}]*"count":\s*2',
|
|
458
|
-
)
|
|
459
|
-
# Verify spread (**kwargs) handling when walker is on left-hand side
|
|
460
|
-
self.assertRegex(
|
|
461
|
-
bundle.code,
|
|
462
|
-
r'__jacSpawn\("positional_walker",\s*"",\s*_objectSpread\(\{\s*"label":\s*"Spread order"[^}]*"count":\s*5\s*\},\s*extra_fields\)',
|
|
463
|
-
)
|
|
464
|
-
|
|
465
|
-
# Verify we have at least 7 __jacSpawn calls (previous cases + new positional/spread)
|
|
466
|
-
self.assertTrue(
|
|
467
|
-
bundle.code.count('__jacSpawn') >= 7,
|
|
468
|
-
"Expected at least 7 __jacSpawn calls in bundle"
|
|
469
|
-
)
|
|
470
|
-
|
|
471
|
-
# Verify bundle was written to output directory
|
|
472
|
-
bundle_files = list(output_dir.glob("client.*.js"))
|
|
473
|
-
self.assertGreater(len(bundle_files), 0, "Expected at least one bundle file")
|
|
474
|
-
|
|
475
|
-
# Cleanup
|
|
476
|
-
builder.cleanup_temp_dir()
|
|
280
|
+
|
|
281
|
+
# Import the test module with relative import
|
|
282
|
+
fixtures_dir = Path(__file__).parent / "fixtures" / "relative_import"
|
|
283
|
+
(module,) = Jac.jac_import("app", str(fixtures_dir))
|
|
284
|
+
|
|
285
|
+
# Build the bundle
|
|
286
|
+
bundle = builder.build(module, force=True)
|
|
287
|
+
|
|
288
|
+
# Verify bundle structure
|
|
289
|
+
assert bundle is not None
|
|
290
|
+
assert bundle.module_name == "app"
|
|
291
|
+
assert "RelativeImport" in bundle.client_functions
|
|
292
|
+
assert "app" in bundle.client_functions
|
|
293
|
+
assert "CustomButton" in bundle.code
|
|
294
|
+
|
|
295
|
+
# Verify bundle code contains expected content
|
|
296
|
+
assert "function RelativeImport()" in bundle.code
|
|
297
|
+
assert "function app()" in bundle.code
|
|
298
|
+
|
|
299
|
+
# Verify that the relative import (Button from .button) is properly resolved
|
|
300
|
+
assert "ButtonGroup" in bundle.code
|
|
301
|
+
|
|
302
|
+
# Verify bundle was written to output directory
|
|
303
|
+
bundle_files = list(output_dir.glob("client.*.js"))
|
|
304
|
+
assert len(bundle_files) > 0, "Expected at least one bundle file"
|
|
305
|
+
|
|
306
|
+
# Cleanup
|
|
307
|
+
builder.cleanup_temp_dir()
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def test_js_import() -> None:
|
|
311
|
+
"""Test that JavaScript file imports work correctly in Vite bundling."""
|
|
312
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
313
|
+
temp_path = Path(temp_dir)
|
|
314
|
+
# Create project with Vite installed
|
|
315
|
+
package_json, output_dir = _create_test_project_with_vite(temp_path)
|
|
316
|
+
runtime_path = Path(__file__).parent.parent / "plugin" / "client_runtime.jac"
|
|
317
|
+
# Initialize the Vite builder
|
|
318
|
+
builder = ViteClientBundleBuilder(
|
|
319
|
+
runtime_path=runtime_path,
|
|
320
|
+
vite_package_json=package_json,
|
|
321
|
+
vite_output_dir=output_dir,
|
|
322
|
+
vite_minify=False,
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
# Import the test module with JavaScript import
|
|
326
|
+
fixtures_dir = Path(__file__).parent / "fixtures" / "js_import"
|
|
327
|
+
(module,) = Jac.jac_import("app", str(fixtures_dir))
|
|
328
|
+
|
|
329
|
+
# Build the bundle
|
|
330
|
+
bundle = builder.build(module, force=True)
|
|
331
|
+
|
|
332
|
+
# Verify bundle structure
|
|
333
|
+
assert bundle is not None
|
|
334
|
+
assert bundle.module_name == "app"
|
|
335
|
+
assert "JsImportTest" in bundle.client_functions
|
|
336
|
+
assert "app" in bundle.client_functions
|
|
337
|
+
assert "JS_IMPORT_LABEL" in bundle.client_globals
|
|
338
|
+
|
|
339
|
+
# Verify bundle code contains expected content
|
|
340
|
+
assert "function JsImportTest()" in bundle.code
|
|
341
|
+
assert "function app()" in bundle.code
|
|
342
|
+
assert 'JS_IMPORT_LABEL = "JavaScript Import Test";' in bundle.code
|
|
343
|
+
|
|
344
|
+
# Verify JavaScript imports are present in the bundle
|
|
345
|
+
# The JavaScript functions should be available in the bundle
|
|
346
|
+
assert "formatMessage" in bundle.code
|
|
347
|
+
assert "calculateSum" in bundle.code
|
|
348
|
+
assert "JS_CONSTANT" in bundle.code
|
|
349
|
+
assert "MessageFormatter" in bundle.code
|
|
350
|
+
|
|
351
|
+
# Verify the JavaScript utility code is included
|
|
352
|
+
assert "Hello," in bundle.code # From formatMessage function
|
|
353
|
+
assert "Imported from JavaScript" in bundle.code # From JS_CONSTANT
|
|
354
|
+
|
|
355
|
+
# Verify bundle was written to output directory
|
|
356
|
+
bundle_files = list(output_dir.glob("client.*.js"))
|
|
357
|
+
assert len(bundle_files) > 0, "Expected at least one bundle file"
|
|
358
|
+
|
|
359
|
+
# Cleanup
|
|
360
|
+
builder.cleanup_temp_dir()
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def test_jsx_fragments_and_spread_props() -> None:
|
|
364
|
+
"""Test that JSX fragments and spread props work correctly."""
|
|
365
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
366
|
+
temp_path = Path(temp_dir)
|
|
367
|
+
|
|
368
|
+
# Create project with Vite installed
|
|
369
|
+
package_json, output_dir = _create_test_project_with_vite(temp_path)
|
|
370
|
+
runtime_path = Path(__file__).parent.parent / "plugin" / "client_runtime.jac"
|
|
371
|
+
|
|
372
|
+
# Initialize the Vite builder
|
|
373
|
+
builder = ViteClientBundleBuilder(
|
|
374
|
+
runtime_path=runtime_path,
|
|
375
|
+
vite_package_json=package_json,
|
|
376
|
+
vite_output_dir=output_dir,
|
|
377
|
+
vite_minify=False,
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
# Import the test module with fragments and spread props
|
|
381
|
+
fixtures_dir = Path(__file__).parent / "fixtures" / "test_fragments_spread"
|
|
382
|
+
(module,) = Jac.jac_import("app", str(fixtures_dir))
|
|
383
|
+
|
|
384
|
+
# Build the bundle
|
|
385
|
+
bundle = builder.build(module, force=True)
|
|
386
|
+
|
|
387
|
+
# Verify bundle structure
|
|
388
|
+
assert bundle is not None
|
|
389
|
+
assert bundle.module_name == "app"
|
|
390
|
+
assert "FragmentTest" in bundle.client_functions
|
|
391
|
+
assert "SpreadPropsTest" in bundle.client_functions
|
|
392
|
+
assert "MixedTest" in bundle.client_functions
|
|
393
|
+
assert "NestedFragments" in bundle.client_functions
|
|
394
|
+
|
|
395
|
+
# Verify spread props handling (Object.assign is used by compiler)
|
|
396
|
+
assert "Object.assign" in bundle.code
|
|
397
|
+
|
|
398
|
+
# Verify fragment test function exists
|
|
399
|
+
assert "function FragmentTest()" in bundle.code
|
|
400
|
+
|
|
401
|
+
# Verify spread props test function exists
|
|
402
|
+
assert "function SpreadPropsTest()" in bundle.code
|
|
403
|
+
|
|
404
|
+
# Verify bundle was written to output directory
|
|
405
|
+
bundle_files = list(output_dir.glob("client.*.js"))
|
|
406
|
+
assert len(bundle_files) > 0, "Expected at least one bundle file"
|
|
407
|
+
|
|
408
|
+
# Cleanup
|
|
409
|
+
builder.cleanup_temp_dir()
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def test_spawn_operator() -> None:
|
|
413
|
+
"""Test that spawn operator generates correct __jacSpawn calls for both orderings and node types (root and UUID)."""
|
|
414
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
415
|
+
temp_path = Path(temp_dir)
|
|
416
|
+
|
|
417
|
+
# Create project with Vite installed
|
|
418
|
+
package_json, output_dir = _create_test_project_with_vite(temp_path)
|
|
419
|
+
runtime_path = Path(__file__).parent.parent / "plugin" / "client_runtime.jac"
|
|
420
|
+
|
|
421
|
+
# Initialize the Vite builder
|
|
422
|
+
builder = ViteClientBundleBuilder(
|
|
423
|
+
runtime_path=runtime_path,
|
|
424
|
+
vite_package_json=package_json,
|
|
425
|
+
vite_output_dir=output_dir,
|
|
426
|
+
vite_minify=False,
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
# Import the test module with both spawn operator orderings
|
|
430
|
+
fixtures_dir = Path(__file__).parent / "fixtures" / "spawn_test"
|
|
431
|
+
(module,) = Jac.jac_import("app", str(fixtures_dir))
|
|
432
|
+
|
|
433
|
+
# Build the bundle
|
|
434
|
+
bundle = builder.build(module, force=True)
|
|
435
|
+
|
|
436
|
+
# Verify bundle structure
|
|
437
|
+
assert bundle is not None
|
|
438
|
+
assert bundle.module_name == "app"
|
|
439
|
+
assert "app" in bundle.client_functions
|
|
440
|
+
|
|
441
|
+
# Verify complete __jacSpawn calls for root spawn scenarios
|
|
442
|
+
# Standard order: root spawn test_walker()
|
|
443
|
+
assert '__jacSpawn("test_walker", "", {})' in bundle.code
|
|
444
|
+
|
|
445
|
+
# Standard order: root spawn parameterized_walker(value=42)
|
|
446
|
+
assert '__jacSpawn("parameterized_walker", "", {' in bundle.code
|
|
447
|
+
assert '"value": 42' in bundle.code
|
|
448
|
+
|
|
449
|
+
# Reverse order: test_walker(message="Reverse spawn!") spawn root
|
|
450
|
+
# Should generate: __jacSpawn("test_walker", "", {message: "Reverse spawn!"})
|
|
451
|
+
import re
|
|
452
|
+
|
|
453
|
+
assert re.search(
|
|
454
|
+
r'__jacSpawn\("test_walker",\s*"",\s*\{[^}]*"message":\s*"Reverse spawn!"[^}]*\}\)',
|
|
455
|
+
bundle.code,
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
# Verify UUID spawn scenarios with complete calls
|
|
459
|
+
# Standard UUID spawn: node_id spawn test_walker()
|
|
460
|
+
# Should generate: __jacSpawn("test_walker", node_id, {})
|
|
461
|
+
assert '__jacSpawn("test_walker", node_id, {})' in bundle.code
|
|
462
|
+
assert '"550e8400-e29b-41d4-a716-446655440000"' in bundle.code
|
|
463
|
+
|
|
464
|
+
# Reverse UUID spawn: parameterized_walker(value=100) spawn another_node_id
|
|
465
|
+
# Should generate: __jacSpawn("parameterized_walker", another_node_id, {value: 100})
|
|
466
|
+
assert re.search(
|
|
467
|
+
r'__jacSpawn\("parameterized_walker",\s*another_node_id,\s*\{[^}]*"value":\s*100[^}]*\}\)',
|
|
468
|
+
bundle.code,
|
|
469
|
+
)
|
|
470
|
+
assert '"6ba7b810-9dad-11d1-80b4-00c04fd430c8"' in bundle.code
|
|
471
|
+
|
|
472
|
+
# Verify positional argument mapping for walkers
|
|
473
|
+
assert re.search(
|
|
474
|
+
r'__jacSpawn\("positional_walker",\s*node_id,\s*\{[^}]*"label":\s*"Node positional"[^}]*"count":\s*2',
|
|
475
|
+
bundle.code,
|
|
476
|
+
)
|
|
477
|
+
# Verify spread (**kwargs) handling when walker is on left-hand side
|
|
478
|
+
assert re.search(
|
|
479
|
+
r'__jacSpawn\("positional_walker",\s*"",\s*_objectSpread\(\{\s*"label":\s*"Spread order"[^}]*"count":\s*5\s*\},\s*extra_fields\)',
|
|
480
|
+
bundle.code,
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
# Verify we have at least 7 __jacSpawn calls (previous cases + new positional/spread)
|
|
484
|
+
assert bundle.code.count("__jacSpawn") >= 7, (
|
|
485
|
+
"Expected at least 7 __jacSpawn calls in bundle"
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
# Verify bundle was written to output directory
|
|
489
|
+
bundle_files = list(output_dir.glob("client.*.js"))
|
|
490
|
+
assert len(bundle_files) > 0, "Expected at least one bundle file"
|
|
491
|
+
|
|
492
|
+
# Cleanup
|
|
493
|
+
builder.cleanup_temp_dir()
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
def test_serve_cl_file() -> None:
|
|
497
|
+
"""Test that serving a .cl file works correctly."""
|
|
498
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
499
|
+
temp_path = Path(temp_dir)
|
|
500
|
+
|
|
501
|
+
# Create project with Vite installed
|
|
502
|
+
package_json, output_dir = _create_test_project_with_vite(temp_path)
|
|
503
|
+
runtime_path = Path(__file__).parent.parent / "plugin" / "client_runtime.jac"
|
|
504
|
+
|
|
505
|
+
# Initialize the Vite builder
|
|
506
|
+
builder = ViteClientBundleBuilder(
|
|
507
|
+
runtime_path=runtime_path,
|
|
508
|
+
vite_package_json=package_json,
|
|
509
|
+
vite_output_dir=output_dir,
|
|
510
|
+
vite_minify=False,
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
# Import the test module with both spawn operator orderings
|
|
514
|
+
fixtures_dir = Path(__file__).parent / "fixtures" / "cl_file"
|
|
515
|
+
(module,) = Jac.jac_import("app", str(fixtures_dir))
|
|
516
|
+
|
|
517
|
+
# Build the bundle
|
|
518
|
+
bundle = builder.build(module, force=True)
|
|
519
|
+
# Verify bundle structure
|
|
520
|
+
assert bundle is not None
|
|
521
|
+
assert bundle.module_name == "app"
|
|
522
|
+
assert "app" in bundle.client_functions
|
|
523
|
+
|
|
524
|
+
assert "function app()" in bundle.code
|
|
525
|
+
assert '__jacJsx("div", {}, [__jacJsx("h2", {}, ["My Todos"])' in bundle.code
|
|
526
|
+
assert "root.render(/* @__PURE__ */ React.c" in bundle.code
|
|
527
|
+
assert "ar _useState = reactExports.useState([]), _useStat" in bundle.code
|
|
528
|
+
assert 'turn __jacSpawn("create_todo", ' in bundle.code
|
|
529
|
+
# Cleanup
|
|
530
|
+
builder.cleanup_temp_dir()
|