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