jac-client 0.2.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.
Files changed (84) hide show
  1. jac_client/docs/README.md +31 -1
  2. jac_client/docs/asset-serving/intro.md +209 -0
  3. jac_client/docs/assets/pipe_line-v2.svg +32 -0
  4. jac_client/docs/file-system/intro.md +90 -0
  5. jac_client/docs/styling/intro.md +250 -0
  6. jac_client/docs/styling/js-styling.md +373 -0
  7. jac_client/docs/styling/material-ui.md +346 -0
  8. jac_client/docs/styling/pure-css.md +305 -0
  9. jac_client/docs/styling/sass.md +409 -0
  10. jac_client/docs/styling/styled-components.md +401 -0
  11. jac_client/docs/styling/tailwind.md +303 -0
  12. jac_client/examples/asset-serving/css-with-image/.babelrc +9 -0
  13. jac_client/examples/asset-serving/css-with-image/README.md +91 -0
  14. jac_client/examples/asset-serving/css-with-image/app.jac +67 -0
  15. jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
  16. jac_client/examples/asset-serving/css-with-image/package.json +28 -0
  17. jac_client/examples/asset-serving/css-with-image/styles.css +27 -0
  18. jac_client/examples/asset-serving/css-with-image/vite.config.js +29 -0
  19. jac_client/examples/asset-serving/image-asset/.babelrc +9 -0
  20. jac_client/examples/asset-serving/image-asset/README.md +119 -0
  21. jac_client/examples/asset-serving/image-asset/app.jac +43 -0
  22. jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
  23. jac_client/examples/asset-serving/image-asset/package.json +28 -0
  24. jac_client/examples/asset-serving/image-asset/styles.css +27 -0
  25. jac_client/examples/asset-serving/image-asset/vite.config.js +29 -0
  26. jac_client/examples/asset-serving/import-alias/.babelrc +9 -0
  27. jac_client/examples/asset-serving/import-alias/README.md +83 -0
  28. jac_client/examples/asset-serving/import-alias/app.jac +57 -0
  29. jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
  30. jac_client/examples/asset-serving/import-alias/package.json +28 -0
  31. jac_client/examples/asset-serving/import-alias/vite.config.js +29 -0
  32. jac_client/examples/css-styling/js-styling/.babelrc +9 -0
  33. jac_client/examples/css-styling/js-styling/README.md +183 -0
  34. jac_client/examples/css-styling/js-styling/app.jac +63 -0
  35. jac_client/examples/css-styling/js-styling/package.json +28 -0
  36. jac_client/examples/css-styling/js-styling/styles.js +100 -0
  37. jac_client/examples/css-styling/js-styling/vite.config.js +28 -0
  38. jac_client/examples/css-styling/material-ui/.babelrc +9 -0
  39. jac_client/examples/css-styling/material-ui/README.md +16 -0
  40. jac_client/examples/css-styling/material-ui/app.jac +82 -0
  41. jac_client/examples/css-styling/material-ui/package.json +32 -0
  42. jac_client/examples/css-styling/material-ui/vite.config.js +28 -0
  43. jac_client/examples/css-styling/pure-css/.babelrc +9 -0
  44. jac_client/examples/css-styling/pure-css/README.md +16 -0
  45. jac_client/examples/css-styling/pure-css/app.jac +63 -0
  46. jac_client/examples/css-styling/pure-css/package.json +28 -0
  47. jac_client/examples/css-styling/pure-css/styles.css +112 -0
  48. jac_client/examples/css-styling/pure-css/vite.config.js +28 -0
  49. jac_client/examples/css-styling/sass-example/.babelrc +9 -0
  50. jac_client/examples/css-styling/sass-example/README.md +16 -0
  51. jac_client/examples/css-styling/sass-example/app.jac +63 -0
  52. jac_client/examples/css-styling/sass-example/package.json +29 -0
  53. jac_client/examples/css-styling/sass-example/styles.scss +158 -0
  54. jac_client/examples/css-styling/sass-example/vite.config.js +28 -0
  55. jac_client/examples/css-styling/styled-components/.babelrc +9 -0
  56. jac_client/examples/css-styling/styled-components/README.md +16 -0
  57. jac_client/examples/css-styling/styled-components/app.jac +66 -0
  58. jac_client/examples/css-styling/styled-components/package.json +29 -0
  59. jac_client/examples/css-styling/styled-components/styled.js +91 -0
  60. jac_client/examples/css-styling/styled-components/vite.config.js +28 -0
  61. jac_client/examples/css-styling/tailwind-example/.babelrc +9 -0
  62. jac_client/examples/css-styling/tailwind-example/README.md +16 -0
  63. jac_client/examples/css-styling/tailwind-example/app.jac +64 -0
  64. jac_client/examples/css-styling/tailwind-example/global.css +1 -0
  65. jac_client/examples/css-styling/tailwind-example/package.json +30 -0
  66. jac_client/examples/css-styling/tailwind-example/vite.config.js +30 -0
  67. jac_client/examples/with-router/app.jac +1 -1
  68. jac_client/plugin/cli.py +5 -0
  69. jac_client/plugin/client.py +64 -3
  70. jac_client/plugin/vite_client_bundle.py +96 -1
  71. jac_client/tests/__init__.py +0 -1
  72. jac_client/tests/fixtures/cl_file/app.cl.jac +38 -0
  73. jac_client/tests/fixtures/cl_file/app.jac +15 -0
  74. jac_client/tests/fixtures/js_import/app.jac +1 -1
  75. jac_client/tests/fixtures/relative_import/button.jac +2 -2
  76. jac_client/tests/fixtures/test_fragments_spread/app.jac +2 -2
  77. jac_client/tests/test_asset_examples.py +339 -0
  78. jac_client/tests/test_cl.py +165 -87
  79. jac_client/tests/test_create_jac_app.py +40 -44
  80. {jac_client-0.2.0.dist-info → jac_client-0.2.1.dist-info}/METADATA +2 -2
  81. jac_client-0.2.1.dist-info/RECORD +140 -0
  82. jac_client-0.2.0.dist-info/RECORD +0 -72
  83. {jac_client-0.2.0.dist-info → jac_client-0.2.1.dist-info}/WHEEL +0 -0
  84. {jac_client-0.2.0.dist-info → jac_client-0.2.1.dist-info}/entry_points.txt +0 -0
@@ -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()