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
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""Test module for spawn operator in both standard and reverse order."""
|
|
2
|
+
|
|
3
|
+
# Server-side node and walker definitions
|
|
4
|
+
node TestNode {
|
|
5
|
+
has value: int = 0;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
walker test_walker {
|
|
9
|
+
has message: str = "Hello from walker";
|
|
10
|
+
|
|
11
|
+
can execute with `root entry {
|
|
12
|
+
report {"result": self.message} ;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
walker parameterized_walker {
|
|
17
|
+
has value: int;
|
|
18
|
+
|
|
19
|
+
can execute with `root entry {
|
|
20
|
+
report {"computed": self.value * 2} ;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
walker positional_walker {
|
|
25
|
+
has label: str;
|
|
26
|
+
has count: int;
|
|
27
|
+
has metadata: dict = {};
|
|
28
|
+
|
|
29
|
+
can execute with `root entry {
|
|
30
|
+
report {
|
|
31
|
+
"label": self.label,
|
|
32
|
+
"count": self.count,
|
|
33
|
+
"meta": self.metadata
|
|
34
|
+
} ;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Client-side code testing both spawn orderings
|
|
39
|
+
cl import from react {
|
|
40
|
+
useState,
|
|
41
|
+
useEffect
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
cl {
|
|
45
|
+
def app() -> any {
|
|
46
|
+
let [standardResult, setStandardResult] = useState(None);
|
|
47
|
+
let [standardComputed, setStandardComputed] = useState(None);
|
|
48
|
+
let [reverseResult, setReverseResult] = useState(None);
|
|
49
|
+
let [uuidResult, setUuidResult] = useState(None);
|
|
50
|
+
let [reverseUuidResult, setReverseUuidResult] = useState(None);
|
|
51
|
+
let [positionalResult, setPositionalResult] = useState(None);
|
|
52
|
+
let [spreadResult, setSpreadResult] = useState(None);
|
|
53
|
+
|
|
54
|
+
async def loadData() -> None {
|
|
55
|
+
# Test standard spawn order: node spawn walker()
|
|
56
|
+
data1 = root spawn test_walker();
|
|
57
|
+
setStandardResult(data1);
|
|
58
|
+
|
|
59
|
+
data2 = root spawn parameterized_walker(value=42);
|
|
60
|
+
setStandardComputed(data2);
|
|
61
|
+
|
|
62
|
+
# Test reverse spawn order: walker() spawn node
|
|
63
|
+
data3 = test_walker(message="Reverse spawn!") spawn root;
|
|
64
|
+
setReverseResult(data3);
|
|
65
|
+
|
|
66
|
+
# Test spawn with UUID string: uuid_string spawn walker()
|
|
67
|
+
node_id = "550e8400-e29b-41d4-a716-446655440000";
|
|
68
|
+
data4 = node_id spawn test_walker();
|
|
69
|
+
setUuidResult(data4);
|
|
70
|
+
|
|
71
|
+
# Test reverse spawn with UUID string: walker() spawn uuid_string
|
|
72
|
+
another_node_id = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
|
|
73
|
+
data5 = parameterized_walker(value=100) spawn another_node_id;
|
|
74
|
+
setReverseUuidResult(data5);
|
|
75
|
+
|
|
76
|
+
# Test positional walker arguments inferred from has fields
|
|
77
|
+
data6 = node_id spawn positional_walker("Node positional", 2);
|
|
78
|
+
setPositionalResult(data6);
|
|
79
|
+
|
|
80
|
+
# Test **kwargs via spread when walker is on left-hand side
|
|
81
|
+
extra_fields = {"metadata": {"source": "client-side"}};
|
|
82
|
+
data7 = positional_walker("Spread order", 5, **extra_fields) spawn root;
|
|
83
|
+
setSpreadResult(data7);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
useEffect(lambda -> None{ loadData();} , []);
|
|
87
|
+
|
|
88
|
+
return <div>
|
|
89
|
+
<h1>
|
|
90
|
+
Spawn Operator Test
|
|
91
|
+
</h1>
|
|
92
|
+
<h2>
|
|
93
|
+
Standard Order (node spawn walker)
|
|
94
|
+
</h2>
|
|
95
|
+
<div>
|
|
96
|
+
Result: {JSON.stringify(standardResult)}
|
|
97
|
+
</div>
|
|
98
|
+
<div>
|
|
99
|
+
Computed: {JSON.stringify(standardComputed)}
|
|
100
|
+
</div>
|
|
101
|
+
<h2>
|
|
102
|
+
Reverse Order (walker spawn node)
|
|
103
|
+
</h2>
|
|
104
|
+
<div>
|
|
105
|
+
Result: {JSON.stringify(reverseResult)}
|
|
106
|
+
</div>
|
|
107
|
+
<h2>
|
|
108
|
+
UUID Spawn (uuid spawn walker)
|
|
109
|
+
</h2>
|
|
110
|
+
<div>
|
|
111
|
+
Result: {JSON.stringify(uuidResult)}
|
|
112
|
+
</div>
|
|
113
|
+
<h2>
|
|
114
|
+
Reverse UUID Spawn (walker spawn uuid)
|
|
115
|
+
</h2>
|
|
116
|
+
<div>
|
|
117
|
+
Result: {JSON.stringify(reverseUuidResult)}
|
|
118
|
+
</div>
|
|
119
|
+
<h2>
|
|
120
|
+
Positional Walker Arguments
|
|
121
|
+
</h2>
|
|
122
|
+
<div>
|
|
123
|
+
Result: {JSON.stringify(positionalResult)}
|
|
124
|
+
</div>
|
|
125
|
+
<h2>
|
|
126
|
+
Spread Walker Arguments
|
|
127
|
+
</h2>
|
|
128
|
+
<div>
|
|
129
|
+
Result: {JSON.stringify(spreadResult)}
|
|
130
|
+
</div>
|
|
131
|
+
</div>;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -11,7 +11,7 @@ cl def FragmentTest() {
|
|
|
11
11
|
cl def SpreadPropsTest() {
|
|
12
12
|
# Test spread props
|
|
13
13
|
unwrapped = {"id": "my-div", "class": "container", "data-role": "main"};
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
return <div {...unwrapped}>
|
|
16
16
|
<span>{"Spread props work!"}</span>
|
|
17
17
|
</div>;
|
|
@@ -20,7 +20,7 @@ cl def SpreadPropsTest() {
|
|
|
20
20
|
cl def MixedTest() {
|
|
21
21
|
# Test mixing spread props with regular props
|
|
22
22
|
baseStyle = {"id": "base-id", "color": "blue"};
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
return <>
|
|
25
25
|
<div {...baseStyle} class="override">
|
|
26
26
|
{"Mixed test"}
|
|
@@ -42,3 +42,12 @@ cl def NestedFragments() {
|
|
|
42
42
|
</div>;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
cl def app() {
|
|
46
|
+
return <div>
|
|
47
|
+
<FragmentTest />
|
|
48
|
+
<SpreadPropsTest />
|
|
49
|
+
<MixedTest />
|
|
50
|
+
<NestedFragments />
|
|
51
|
+
</div>;
|
|
52
|
+
}
|
|
53
|
+
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"""Tests for asset-serving and css-styling examples."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import json
|
|
7
|
+
import shutil
|
|
8
|
+
import tempfile
|
|
9
|
+
import subprocess
|
|
10
|
+
|
|
11
|
+
from jaclang.runtimelib.machine import JacMachine as Jac
|
|
12
|
+
from jaclang.utils.test import TestCase
|
|
13
|
+
from jac_client.plugin.vite_client_bundle import ViteClientBundleBuilder
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AssetServingExampleTests(TestCase):
|
|
17
|
+
"""Test asset-serving examples."""
|
|
18
|
+
|
|
19
|
+
def setUp(self) -> None:
|
|
20
|
+
Jac.reset_machine()
|
|
21
|
+
return super().setUp()
|
|
22
|
+
|
|
23
|
+
def tearDown(self) -> None:
|
|
24
|
+
Jac.reset_machine()
|
|
25
|
+
return super().tearDown()
|
|
26
|
+
|
|
27
|
+
def _create_test_project_with_vite(
|
|
28
|
+
self, temp_path: Path, include_assets: bool = False
|
|
29
|
+
) -> tuple[Path, Path]:
|
|
30
|
+
"""Create a minimal test project with Vite installed.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
temp_path: Path to the temporary directory
|
|
34
|
+
include_assets: If True, includes asset handling setup
|
|
35
|
+
"""
|
|
36
|
+
# Create package.json with base dependencies
|
|
37
|
+
package_data = {
|
|
38
|
+
"name": "test-client",
|
|
39
|
+
"version": "0.0.1",
|
|
40
|
+
"type": "module",
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "npm run compile && vite build",
|
|
43
|
+
"dev": "vite dev",
|
|
44
|
+
"preview": "vite preview",
|
|
45
|
+
"compile": 'babel src --out-dir build --extensions ".jsx,.js" --out-file-extension .js',
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"react": "^19.2.0",
|
|
49
|
+
"react-dom": "^19.2.0",
|
|
50
|
+
"react-router-dom": "^7.3.0",
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"vite": "^6.4.1",
|
|
54
|
+
"@babel/cli": "^7.28.3",
|
|
55
|
+
"@babel/core": "^7.28.5",
|
|
56
|
+
"@babel/preset-env": "^7.28.5",
|
|
57
|
+
"@babel/preset-react": "^7.28.5",
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
package_json = temp_path / "package.json"
|
|
62
|
+
with package_json.open("w", encoding="utf-8") as f:
|
|
63
|
+
json.dump(package_data, f, indent=2)
|
|
64
|
+
|
|
65
|
+
# Create .babelrc file
|
|
66
|
+
babelrc = temp_path / ".babelrc"
|
|
67
|
+
babelrc.write_text(
|
|
68
|
+
"""{
|
|
69
|
+
"presets": [[
|
|
70
|
+
"@babel/preset-env",
|
|
71
|
+
{
|
|
72
|
+
"modules": false
|
|
73
|
+
}
|
|
74
|
+
], "@babel/preset-react"]
|
|
75
|
+
}
|
|
76
|
+
""",
|
|
77
|
+
encoding="utf-8",
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Create vite.config.js file
|
|
81
|
+
vite_config = temp_path / "vite.config.js"
|
|
82
|
+
if include_assets:
|
|
83
|
+
vite_config.write_text(
|
|
84
|
+
"""import { defineConfig } from "vite";
|
|
85
|
+
import path from "path";
|
|
86
|
+
import { fileURLToPath } from "url";
|
|
87
|
+
|
|
88
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
89
|
+
|
|
90
|
+
export default defineConfig({
|
|
91
|
+
root: ".",
|
|
92
|
+
build: {
|
|
93
|
+
rollupOptions: {
|
|
94
|
+
input: "build/main.js",
|
|
95
|
+
output: {
|
|
96
|
+
entryFileNames: "client.[hash].js",
|
|
97
|
+
assetFileNames: "[name].[ext]",
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
outDir: "dist",
|
|
101
|
+
emptyOutDir: true,
|
|
102
|
+
minify: false,
|
|
103
|
+
},
|
|
104
|
+
publicDir: false,
|
|
105
|
+
resolve: {
|
|
106
|
+
alias: {
|
|
107
|
+
"@jac-client/utils": path.resolve(__dirname, "src/client_runtime.js"),
|
|
108
|
+
"@jac-client/assets": path.resolve(__dirname, "src/assets"),
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
""",
|
|
113
|
+
encoding="utf-8",
|
|
114
|
+
)
|
|
115
|
+
else:
|
|
116
|
+
vite_config.write_text(
|
|
117
|
+
"""import { defineConfig } from "vite";
|
|
118
|
+
import path from "path";
|
|
119
|
+
import { fileURLToPath } from "url";
|
|
120
|
+
|
|
121
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
122
|
+
|
|
123
|
+
export default defineConfig({
|
|
124
|
+
root: ".",
|
|
125
|
+
build: {
|
|
126
|
+
rollupOptions: {
|
|
127
|
+
input: "build/main.js",
|
|
128
|
+
output: {
|
|
129
|
+
entryFileNames: "client.[hash].js",
|
|
130
|
+
assetFileNames: "[name].[ext]",
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
outDir: "dist",
|
|
134
|
+
emptyOutDir: true,
|
|
135
|
+
minify: false,
|
|
136
|
+
},
|
|
137
|
+
publicDir: false,
|
|
138
|
+
resolve: {
|
|
139
|
+
alias: {
|
|
140
|
+
"@jac-client/utils": path.resolve(__dirname, "src/client_runtime.js"),
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
""",
|
|
145
|
+
encoding="utf-8",
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# Install dependencies
|
|
149
|
+
result = subprocess.run(
|
|
150
|
+
["npm", "install"],
|
|
151
|
+
cwd=temp_path,
|
|
152
|
+
check=False,
|
|
153
|
+
capture_output=True,
|
|
154
|
+
text=True,
|
|
155
|
+
)
|
|
156
|
+
if result.returncode != 0:
|
|
157
|
+
error_msg = f"npm install failed with exit code {result.returncode}\n"
|
|
158
|
+
error_msg += f"stdout: {result.stdout}\n"
|
|
159
|
+
error_msg += f"stderr: {result.stderr}\n"
|
|
160
|
+
raise RuntimeError(error_msg)
|
|
161
|
+
|
|
162
|
+
# Create output directory
|
|
163
|
+
output_dir = temp_path / "dist"
|
|
164
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
165
|
+
|
|
166
|
+
src_dir = temp_path / "src"
|
|
167
|
+
src_dir.mkdir(parents=True, exist_ok=True)
|
|
168
|
+
|
|
169
|
+
build_dir = temp_path / "build"
|
|
170
|
+
build_dir.mkdir(parents=True, exist_ok=True)
|
|
171
|
+
|
|
172
|
+
return package_json, output_dir
|
|
173
|
+
|
|
174
|
+
def test_image_asset_example(self) -> None:
|
|
175
|
+
"""Test image-asset example with static asset paths."""
|
|
176
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
177
|
+
temp_path = Path(temp_dir)
|
|
178
|
+
|
|
179
|
+
package_json, output_dir = self._create_test_project_with_vite(
|
|
180
|
+
temp_path, include_assets=True
|
|
181
|
+
)
|
|
182
|
+
runtime_path = (
|
|
183
|
+
Path(__file__).parent.parent / "plugin" / "client_runtime.jac"
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
# Initialize the Vite builder
|
|
187
|
+
builder = ViteClientBundleBuilder(
|
|
188
|
+
runtime_path=runtime_path,
|
|
189
|
+
vite_package_json=package_json,
|
|
190
|
+
vite_output_dir=output_dir,
|
|
191
|
+
vite_minify=False,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Import the image-asset example
|
|
195
|
+
examples_dir = (
|
|
196
|
+
Path(__file__).parent.parent
|
|
197
|
+
/ "examples"
|
|
198
|
+
/ "asset-serving"
|
|
199
|
+
/ "image-asset"
|
|
200
|
+
)
|
|
201
|
+
(module,) = Jac.jac_import("app", str(examples_dir))
|
|
202
|
+
|
|
203
|
+
# Build the bundle
|
|
204
|
+
bundle = builder.build(module, force=True)
|
|
205
|
+
|
|
206
|
+
# Verify bundle structure
|
|
207
|
+
self.assertIsNotNone(bundle)
|
|
208
|
+
self.assertEqual(bundle.module_name, "app")
|
|
209
|
+
self.assertIn("app", bundle.client_functions)
|
|
210
|
+
|
|
211
|
+
# Verify image path is in the bundle
|
|
212
|
+
self.assertIn("/static/assets/burger.png", bundle.code)
|
|
213
|
+
|
|
214
|
+
# Verify bundle was written to output directory
|
|
215
|
+
bundle_files = list(output_dir.glob("client.*.js"))
|
|
216
|
+
self.assertGreater(
|
|
217
|
+
len(bundle_files), 0, "Expected at least one bundle file"
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# Cleanup
|
|
221
|
+
builder.cleanup_temp_dir()
|
|
222
|
+
|
|
223
|
+
def test_css_with_image_example(self) -> None:
|
|
224
|
+
"""Test css-with-image example with CSS and image assets."""
|
|
225
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
226
|
+
temp_path = Path(temp_dir)
|
|
227
|
+
|
|
228
|
+
package_json, output_dir = self._create_test_project_with_vite(
|
|
229
|
+
temp_path, include_assets=True
|
|
230
|
+
)
|
|
231
|
+
runtime_path = (
|
|
232
|
+
Path(__file__).parent.parent / "plugin" / "client_runtime.jac"
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
# Initialize the Vite builder
|
|
236
|
+
builder = ViteClientBundleBuilder(
|
|
237
|
+
runtime_path=runtime_path,
|
|
238
|
+
vite_package_json=package_json,
|
|
239
|
+
vite_output_dir=output_dir,
|
|
240
|
+
vite_minify=False,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
# Import the css-with-image example
|
|
244
|
+
examples_dir = (
|
|
245
|
+
Path(__file__).parent.parent
|
|
246
|
+
/ "examples"
|
|
247
|
+
/ "asset-serving"
|
|
248
|
+
/ "css-with-image"
|
|
249
|
+
)
|
|
250
|
+
(module,) = Jac.jac_import("app", str(examples_dir))
|
|
251
|
+
|
|
252
|
+
# Build the bundle
|
|
253
|
+
bundle = builder.build(module, force=True)
|
|
254
|
+
|
|
255
|
+
# Verify bundle structure
|
|
256
|
+
self.assertIsNotNone(bundle)
|
|
257
|
+
self.assertEqual(bundle.module_name, "app")
|
|
258
|
+
self.assertIn("app", bundle.client_functions)
|
|
259
|
+
|
|
260
|
+
# Verify CSS import is present (CSS should be extracted to separate file)
|
|
261
|
+
# The bundle should reference the CSS file
|
|
262
|
+
self.assertIn("import", bundle.code.lower())
|
|
263
|
+
|
|
264
|
+
# Verify image paths are in the bundle
|
|
265
|
+
self.assertIn("/static/assets/burger.png", bundle.code)
|
|
266
|
+
|
|
267
|
+
# Verify CSS file was extracted
|
|
268
|
+
css_files = list(output_dir.glob("*.css"))
|
|
269
|
+
self.assertGreater(len(css_files), 0, "Expected at least one CSS file")
|
|
270
|
+
|
|
271
|
+
# Verify bundle was written to output directory
|
|
272
|
+
bundle_files = list(output_dir.glob("client.*.js"))
|
|
273
|
+
self.assertGreater(
|
|
274
|
+
len(bundle_files), 0, "Expected at least one bundle file"
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
# Cleanup
|
|
278
|
+
builder.cleanup_temp_dir()
|
|
279
|
+
|
|
280
|
+
def test_import_alias_example(self) -> None:
|
|
281
|
+
"""Test import-alias example with @jac-client/assets alias."""
|
|
282
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
283
|
+
temp_path = Path(temp_dir)
|
|
284
|
+
package_json, output_dir = self._create_test_project_with_vite(
|
|
285
|
+
temp_path, include_assets=True
|
|
286
|
+
)
|
|
287
|
+
runtime_path = (
|
|
288
|
+
Path(__file__).parent.parent / "plugin" / "client_runtime.jac"
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
# Initialize the Vite builder
|
|
292
|
+
builder = ViteClientBundleBuilder(
|
|
293
|
+
runtime_path=runtime_path,
|
|
294
|
+
vite_package_json=package_json,
|
|
295
|
+
vite_output_dir=output_dir,
|
|
296
|
+
vite_minify=False,
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
# Import the import-alias example
|
|
300
|
+
examples_dir = (
|
|
301
|
+
Path(__file__).parent.parent
|
|
302
|
+
/ "examples"
|
|
303
|
+
/ "asset-serving"
|
|
304
|
+
/ "import-alias"
|
|
305
|
+
)
|
|
306
|
+
(module,) = Jac.jac_import("app", str(examples_dir))
|
|
307
|
+
|
|
308
|
+
# Copy assets from example directory to temp project's src/assets/
|
|
309
|
+
# This is needed because @jac-client/assets alias points to src/assets
|
|
310
|
+
example_assets_dir = examples_dir / "assets"
|
|
311
|
+
temp_assets_dir = temp_path / "src" / "assets"
|
|
312
|
+
if example_assets_dir.exists():
|
|
313
|
+
temp_assets_dir.mkdir(parents=True, exist_ok=True)
|
|
314
|
+
# Copy all files from example assets to temp assets
|
|
315
|
+
for asset_file in example_assets_dir.iterdir():
|
|
316
|
+
if asset_file.is_file():
|
|
317
|
+
shutil.copy2(asset_file, temp_assets_dir / asset_file.name)
|
|
318
|
+
|
|
319
|
+
# Build the bundle
|
|
320
|
+
bundle = builder.build(module, force=True)
|
|
321
|
+
|
|
322
|
+
# Verify bundle structure
|
|
323
|
+
self.assertIsNotNone(bundle)
|
|
324
|
+
self.assertEqual(bundle.module_name, "app")
|
|
325
|
+
self.assertIn("app", bundle.client_functions)
|
|
326
|
+
|
|
327
|
+
# Verify the import alias was processed by Vite
|
|
328
|
+
# Vite should have resolved the asset import
|
|
329
|
+
# The bundle should contain the processed asset URL
|
|
330
|
+
self.assertIn("burgerImage", bundle.code)
|
|
331
|
+
|
|
332
|
+
# Verify bundle was written to output directory
|
|
333
|
+
bundle_files = list(output_dir.glob("client.*.js"))
|
|
334
|
+
self.assertGreater(
|
|
335
|
+
len(bundle_files), 0, "Expected at least one bundle file"
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
# Cleanup
|
|
339
|
+
builder.cleanup_temp_dir()
|