jac-client 0.1.0__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 (33) hide show
  1. jac_client/docs/README.md +629 -0
  2. jac_client/docs/advanced-state.md +706 -0
  3. jac_client/docs/imports.md +650 -0
  4. jac_client/docs/lifecycle-hooks.md +554 -0
  5. jac_client/docs/routing.md +530 -0
  6. jac_client/examples/little-x/app.jac +615 -0
  7. jac_client/examples/little-x/package-lock.json +2840 -0
  8. jac_client/examples/little-x/package.json +23 -0
  9. jac_client/examples/little-x/submit-button.jac +8 -0
  10. jac_client/examples/todo-app/README.md +82 -0
  11. jac_client/examples/todo-app/app.jac +683 -0
  12. jac_client/examples/todo-app/package-lock.json +999 -0
  13. jac_client/examples/todo-app/package.json +22 -0
  14. jac_client/plugin/cli.py +328 -0
  15. jac_client/plugin/client.py +41 -0
  16. jac_client/plugin/client_runtime.jac +941 -0
  17. jac_client/plugin/vite_client_bundle.py +470 -0
  18. jac_client/tests/__init__.py +2 -0
  19. jac_client/tests/fixtures/button.jac +6 -0
  20. jac_client/tests/fixtures/client_app.jac +18 -0
  21. jac_client/tests/fixtures/client_app_with_antd.jac +21 -0
  22. jac_client/tests/fixtures/js_import.jac +30 -0
  23. jac_client/tests/fixtures/package-lock.json +329 -0
  24. jac_client/tests/fixtures/package.json +11 -0
  25. jac_client/tests/fixtures/relative_import.jac +13 -0
  26. jac_client/tests/fixtures/test_fragments_spread.jac +44 -0
  27. jac_client/tests/fixtures/utils.js +22 -0
  28. jac_client/tests/test_cl.py +360 -0
  29. jac_client/tests/test_create_jac_app.py +139 -0
  30. jac_client-0.1.0.dist-info/METADATA +126 -0
  31. jac_client-0.1.0.dist-info/RECORD +33 -0
  32. jac_client-0.1.0.dist-info/WHEEL +4 -0
  33. jac_client-0.1.0.dist-info/entry_points.txt +4 -0
@@ -0,0 +1,360 @@
1
+ """Tests for Vite client bundle generation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ import tempfile
7
+ import subprocess
8
+
9
+ from jaclang.runtimelib.machine import JacMachine as Jac
10
+ from jaclang.utils.test import TestCase
11
+ from jac_client.plugin.vite_client_bundle import ViteClientBundleBuilder
12
+
13
+
14
+ class ViteClientBundleBuilderTests(TestCase):
15
+ """Validate Vite-powered client bundle compilation."""
16
+
17
+ def setUp(self) -> None:
18
+ Jac.reset_machine()
19
+ return super().setUp()
20
+
21
+ def tearDown(self) -> None:
22
+ Jac.reset_machine()
23
+ return super().tearDown()
24
+
25
+ def _create_test_project_with_vite(self, temp_path: Path, include_antd: bool = False) -> tuple[Path, Path]:
26
+ """Create a minimal test project with Vite installed.
27
+
28
+ Args:
29
+ temp_path: Path to the temporary directory
30
+ include_antd: If True, includes antd in dependencies
31
+ """
32
+ # Create package.json with base dependencies
33
+ dependencies = {
34
+ "react": "^18.0.0",
35
+ "react-dom": "^18.0.0"
36
+ }
37
+
38
+ # Add antd if requested
39
+ if include_antd:
40
+ dependencies["antd"] = "^5.0.0"
41
+
42
+ # Format dependencies for JSON
43
+ deps_str = ",\n".join(f' "{k}": "{v}"' for k, v in dependencies.items())
44
+
45
+ package_json = temp_path / "package.json"
46
+ package_json.write_text(f"""{{
47
+ "name": "test-client",
48
+ "version": "0.0.1",
49
+ "dependencies": {{
50
+ {deps_str}
51
+ }},
52
+ "devDependencies": {{
53
+ "vite": "^5.0.0"
54
+ }}
55
+ }}""", encoding="utf-8")
56
+
57
+ # Install dependencies
58
+ subprocess.run(
59
+ ["npm", "install"],
60
+ cwd=temp_path,
61
+ check=True,
62
+ capture_output=True,
63
+ )
64
+
65
+ # Create output directory
66
+ output_dir = temp_path / "static" / "client" / "js"
67
+ output_dir.mkdir(parents=True, exist_ok=True)
68
+
69
+ temp_dir = temp_path / "temp"
70
+ temp_dir.mkdir(parents=True, exist_ok=True)
71
+
72
+ return package_json, output_dir
73
+
74
+ def test_build_bundle_with_vite(self) -> None:
75
+ """Test that Vite bundling produces optimized output with proper structure."""
76
+ # Create a temporary directory for our test project
77
+ with tempfile.TemporaryDirectory() as temp_dir:
78
+ temp_path = Path(temp_dir)
79
+
80
+ # Create project with Vite installed
81
+ package_json, output_dir = self._create_test_project_with_vite(temp_path)
82
+
83
+ # Initialize the Vite builder
84
+ builder = ViteClientBundleBuilder(
85
+ vite_package_json=package_json,
86
+ vite_output_dir=output_dir,
87
+ vite_minify=False, # Disable minification for easier inspection
88
+ )
89
+
90
+ # Import the test module
91
+ fixtures_dir = Path(__file__).parent / "fixtures"
92
+ (module,) = Jac.jac_import("client_app", str(fixtures_dir))
93
+
94
+ # Build the bundle
95
+ bundle = builder.build(module, force=True)
96
+
97
+ # Verify bundle structure
98
+ self.assertIsNotNone(bundle)
99
+ self.assertEqual(bundle.module_name, "client_app")
100
+ self.assertIn("client_page", bundle.client_functions)
101
+ self.assertIn("ButtonProps", bundle.client_functions)
102
+ self.assertIn("API_LABEL", bundle.client_globals)
103
+ self.assertGreater(len(bundle.hash), 10)
104
+
105
+ # Verify bundle code contains expected content
106
+ self.assertIn("function client_page()", bundle.code)
107
+ self.assertIn('const API_LABEL = "Runtime Test";', bundle.code)
108
+
109
+ # Verify the Jac initialization is present
110
+ self.assertIn("__jacRegisterClientModule", bundle.code)
111
+ self.assertIn("globalThis.start_app", bundle.code)
112
+
113
+ # Verify bundle was written to output directory
114
+ bundle_files = list(output_dir.glob("client.*.js"))
115
+ self.assertGreater(len(bundle_files), 0, "Expected at least one bundle file")
116
+
117
+ # Verify cached bundle is identical
118
+ cached = builder.build(module, force=False)
119
+ self.assertEqual(bundle.hash, cached.hash)
120
+ self.assertEqual(bundle.code, cached.code)
121
+
122
+ def test_vite_bundle_without_package_json(self) -> None:
123
+ """Test that missing package.json raises appropriate error."""
124
+ fixtures_dir = Path(__file__).parent / "fixtures"
125
+ (module,) = Jac.jac_import("client_app", str(fixtures_dir))
126
+
127
+ # Create builder without package.json
128
+ builder = ViteClientBundleBuilder(
129
+ vite_package_json=Path("/nonexistent/package.json"),
130
+ vite_output_dir=Path("/tmp/output"),
131
+ )
132
+
133
+ # Building should raise an error
134
+ from jaclang.runtimelib.client_bundle import ClientBundleError
135
+ with self.assertRaises(ClientBundleError) as cm:
136
+ builder.build(module, force=True)
137
+
138
+ self.assertIn("Vite package.json not found", str(cm.exception))
139
+
140
+ def test_global_exposure_in_bundle(self) -> None:
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()
168
+
169
+ def test_build_bundle_with_antd(self) -> None:
170
+ """Test that Vite bundling works with Ant Design components."""
171
+ with tempfile.TemporaryDirectory() as temp_dir:
172
+ temp_path = Path(temp_dir)
173
+
174
+ # Create project with Vite and Ant Design installed
175
+ package_json, output_dir = self._create_test_project_with_vite(temp_path, include_antd=True)
176
+
177
+ # Initialize the Vite builder
178
+ builder = ViteClientBundleBuilder(
179
+ vite_package_json=package_json,
180
+ vite_output_dir=output_dir,
181
+ vite_minify=False,
182
+ )
183
+
184
+ # Import the test module with Ant Design
185
+ fixtures_dir = Path(__file__).parent / "fixtures"
186
+ (module,) = Jac.jac_import("client_app_with_antd", str(fixtures_dir))
187
+
188
+ # Build the bundle
189
+ bundle = builder.build(module, force=True)
190
+
191
+ # Verify bundle structure
192
+ self.assertIsNotNone(bundle)
193
+ self.assertEqual(bundle.module_name, "client_app_with_antd")
194
+ self.assertIn("ButtonTest", bundle.client_functions)
195
+ self.assertIn("CardTest", bundle.client_functions)
196
+ self.assertIn("APP_NAME", bundle.client_globals)
197
+
198
+ # Verify bundle code contains expected content
199
+ self.assertIn("function ButtonTest()", bundle.code)
200
+ self.assertIn("function CardTest()", bundle.code)
201
+ self.assertIn('const APP_NAME = "Ant Design Test";', bundle.code)
202
+
203
+ # verify antd components are present
204
+ self.assertIn("ButtonGroup", bundle.code)
205
+
206
+ # Verify the Ant Design fixture content is present
207
+ self.assertIn("Testing Ant Design integration", bundle.code)
208
+
209
+ # Verify bundle was written to output directory
210
+ bundle_files = list(output_dir.glob("client.*.js"))
211
+ self.assertGreater(len(bundle_files), 0, "Expected at least one bundle file")
212
+
213
+ # Cleanup
214
+ builder.cleanup_temp_dir()
215
+
216
+ def test_relative_import(self) -> None:
217
+ """Test that relative imports work correctly in Vite bundling."""
218
+ with tempfile.TemporaryDirectory() as temp_dir:
219
+ temp_path = Path(temp_dir)
220
+
221
+ # Create project with Vite installed
222
+ package_json, output_dir = self._create_test_project_with_vite(temp_path, include_antd=True)
223
+
224
+ # Initialize the Vite builder
225
+ builder = ViteClientBundleBuilder(
226
+ vite_package_json=package_json,
227
+ vite_output_dir=output_dir,
228
+ vite_minify=False,
229
+ )
230
+
231
+ # Import the test module with relative import
232
+ fixtures_dir = Path(__file__).parent / "fixtures"
233
+ (module,) = Jac.jac_import("relative_import", str(fixtures_dir))
234
+
235
+ # Build the bundle
236
+ bundle = builder.build(module, force=True)
237
+
238
+ # Verify bundle structure
239
+ self.assertIsNotNone(bundle)
240
+ self.assertEqual(bundle.module_name, "relative_import")
241
+ self.assertIn("RelativeImport", bundle.client_functions)
242
+ self.assertIn("main", bundle.client_functions)
243
+ self.assertIn("CustomButton", bundle.code)
244
+
245
+ # Verify bundle code contains expected content
246
+ self.assertIn("function RelativeImport()", bundle.code)
247
+ self.assertIn("function main()", bundle.code)
248
+
249
+ # Verify that the relative import (Button from .button) is properly resolved
250
+ self.assertIn("ButtonGroup", bundle.code)
251
+
252
+ # Verify the Jac initialization is present
253
+ self.assertIn("__jacRegisterClientModule", bundle.code)
254
+
255
+ # Verify bundle was written to output directory
256
+ bundle_files = list(output_dir.glob("client.*.js"))
257
+ self.assertGreater(len(bundle_files), 0, "Expected at least one bundle file")
258
+
259
+ # Cleanup
260
+ builder.cleanup_temp_dir()
261
+
262
+ def test_js_import(self) -> None:
263
+ """Test that JavaScript file imports work correctly in Vite bundling."""
264
+ with tempfile.TemporaryDirectory() as temp_dir:
265
+ temp_path = Path(temp_dir)
266
+ # Create project with Vite installed
267
+ package_json, output_dir = self._create_test_project_with_vite(temp_path)
268
+
269
+ # Initialize the Vite builder
270
+ builder = ViteClientBundleBuilder(
271
+ vite_package_json=package_json,
272
+ vite_output_dir=output_dir,
273
+ vite_minify=False,
274
+ )
275
+
276
+ # Import the test module with JavaScript import
277
+ fixtures_dir = Path(__file__).parent / "fixtures"
278
+ (module,) = Jac.jac_import("js_import", str(fixtures_dir))
279
+
280
+ # Build the bundle
281
+ bundle = builder.build(module, force=True)
282
+
283
+ # Verify bundle structure
284
+ self.assertIsNotNone(bundle)
285
+ self.assertEqual(bundle.module_name, "js_import")
286
+ self.assertIn("JsImportTest", bundle.client_functions)
287
+ self.assertIn("Main", bundle.client_functions)
288
+ self.assertIn("JS_IMPORT_LABEL", bundle.client_globals)
289
+
290
+ # Verify bundle code contains expected content
291
+ self.assertIn("function JsImportTest()", bundle.code)
292
+ self.assertIn("function Main()", bundle.code)
293
+ self.assertIn('const JS_IMPORT_LABEL = "JavaScript Import Test";', bundle.code)
294
+
295
+ # Verify JavaScript imports are present in the bundle
296
+ # The JavaScript functions should be available in the bundle
297
+ self.assertIn("formatMessage", bundle.code)
298
+ self.assertIn("calculateSum", bundle.code)
299
+ self.assertIn("JS_CONSTANT", bundle.code)
300
+ self.assertIn("MessageFormatter", bundle.code)
301
+
302
+ # Verify the JavaScript utility code is included
303
+ self.assertIn("Hello,", bundle.code) # From formatMessage function
304
+ 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
+
309
+ # Verify bundle was written to output directory
310
+ bundle_files = list(output_dir.glob("client.*.js"))
311
+ self.assertGreater(len(bundle_files), 0, "Expected at least one bundle file")
312
+
313
+ # Cleanup
314
+ builder.cleanup_temp_dir()
315
+
316
+ def test_jsx_fragments_and_spread_props(self) -> None:
317
+ """Test that JSX fragments and spread props work correctly."""
318
+ with tempfile.TemporaryDirectory() as temp_dir:
319
+ temp_path = Path(temp_dir)
320
+
321
+ # Create project with Vite installed
322
+ package_json, output_dir = self._create_test_project_with_vite(temp_path)
323
+
324
+ # Initialize the Vite builder
325
+ builder = ViteClientBundleBuilder(
326
+ vite_package_json=package_json,
327
+ vite_output_dir=output_dir,
328
+ vite_minify=False,
329
+ )
330
+
331
+ # Import the test module with fragments and spread props
332
+ fixtures_dir = Path(__file__).parent / "fixtures"
333
+ (module,) = Jac.jac_import("test_fragments_spread", str(fixtures_dir))
334
+
335
+ # Build the bundle
336
+ bundle = builder.build(module, force=True)
337
+
338
+ # Verify bundle structure
339
+ self.assertIsNotNone(bundle)
340
+ self.assertEqual(bundle.module_name, "test_fragments_spread")
341
+ self.assertIn("FragmentTest", bundle.client_functions)
342
+ self.assertIn("SpreadPropsTest", bundle.client_functions)
343
+ self.assertIn("MixedTest", bundle.client_functions)
344
+ self.assertIn("NestedFragments", bundle.client_functions)
345
+
346
+ # Verify spread props handling (Object.assign is used by compiler)
347
+ self.assertIn("Object.assign", bundle.code)
348
+
349
+ # Verify fragment test function exists
350
+ self.assertIn("function FragmentTest()", bundle.code)
351
+
352
+ # Verify spread props test function exists
353
+ self.assertIn("function SpreadPropsTest()", bundle.code)
354
+
355
+ # Verify bundle was written to output directory
356
+ bundle_files = list(output_dir.glob("client.*.js"))
357
+ self.assertGreater(len(bundle_files), 0, "Expected at least one bundle file")
358
+
359
+ # Cleanup
360
+ builder.cleanup_temp_dir()
@@ -0,0 +1,139 @@
1
+ """Test create-jac-app command."""
2
+
3
+ import json
4
+ import os
5
+ import tempfile
6
+ from subprocess import run
7
+ from unittest import TestCase
8
+
9
+
10
+ class TestCreateJacApp(TestCase):
11
+ """Test create-jac-app command functionality."""
12
+
13
+ def test_create_jac_app(self) -> None:
14
+ """Test create-jac-app command."""
15
+ test_project_name = "test-jac-app"
16
+
17
+ # Create a temporary directory for testing
18
+ with tempfile.TemporaryDirectory() as temp_dir:
19
+ original_cwd = os.getcwd()
20
+ try:
21
+ # Change to temp directory
22
+ os.chdir(temp_dir)
23
+
24
+ # Run create-jac-app command
25
+ result = run(
26
+ [
27
+ "jac",
28
+ "create_jac_app",
29
+ test_project_name
30
+ ],
31
+ capture_output=True,
32
+ text=True,
33
+ check=True
34
+ )
35
+
36
+ # Check that command succeeded
37
+ self.assertEqual(result.returncode, 0)
38
+ self.assertIn(f"Successfully created Jac application '{test_project_name}'!", result.stdout)
39
+
40
+ # Verify project directory was created
41
+ project_path = os.path.join(temp_dir, test_project_name)
42
+ self.assertTrue(os.path.exists(project_path))
43
+ self.assertTrue(os.path.isdir(project_path))
44
+
45
+ # Verify package.json was created and has correct content
46
+ package_json_path = os.path.join(project_path, "package.json")
47
+ self.assertTrue(os.path.exists(package_json_path))
48
+
49
+ with open(package_json_path, "r") as f:
50
+ package_data = json.load(f)
51
+
52
+ self.assertEqual(package_data["name"], test_project_name)
53
+ self.assertEqual(package_data["type"], "module")
54
+ self.assertIn("vite", package_data["devDependencies"])
55
+ self.assertIn("build", package_data["scripts"])
56
+ self.assertIn("dev", package_data["scripts"])
57
+ self.assertIn("preview", package_data["scripts"])
58
+
59
+ # Verify app.jac file was created
60
+ app_jac_path = os.path.join(project_path, "app.jac")
61
+ self.assertTrue(os.path.exists(app_jac_path))
62
+
63
+ with open(app_jac_path, "r") as f:
64
+ app_jac_content = f.read()
65
+
66
+ self.assertIn("jac_app()", app_jac_content)
67
+
68
+ # Verify README.md was created
69
+ readme_path = os.path.join(project_path, "README.md")
70
+ self.assertTrue(os.path.exists(readme_path))
71
+
72
+ with open(readme_path, "r") as f:
73
+ readme_content = f.read()
74
+
75
+ self.assertIn(f"# {test_project_name}", readme_content)
76
+ self.assertIn("jac serve app.jac", readme_content)
77
+
78
+ # Verify node_modules was created (npm install ran)
79
+ node_modules_path = os.path.join(project_path, "node_modules")
80
+ self.assertTrue(os.path.exists(node_modules_path))
81
+
82
+ finally:
83
+ # Return to original directory
84
+ os.chdir(original_cwd)
85
+
86
+ def test_create_jac_app_invalid_name(self) -> None:
87
+ """Test create-jac-app command with invalid project name."""
88
+ with tempfile.TemporaryDirectory() as temp_dir:
89
+ original_cwd = os.getcwd()
90
+ try:
91
+ os.chdir(temp_dir)
92
+
93
+ # Test with invalid name containing spaces
94
+ result = run(
95
+ [
96
+ "jac",
97
+ "create_jac_app",
98
+ "invalid name with spaces"
99
+ ],
100
+ capture_output=True,
101
+ text=True
102
+ )
103
+
104
+ # Should fail with non-zero exit code
105
+ self.assertNotEqual(result.returncode, 0)
106
+ self.assertIn("Project name must contain only letters, numbers, hyphens, and underscores", result.stderr)
107
+
108
+ finally:
109
+ os.chdir(original_cwd)
110
+
111
+ def test_create_jac_app_existing_directory(self) -> None:
112
+ """Test create-jac-app command when directory already exists."""
113
+ test_project_name = "existing-test-app"
114
+
115
+ with tempfile.TemporaryDirectory() as temp_dir:
116
+ original_cwd = os.getcwd()
117
+ try:
118
+ os.chdir(temp_dir)
119
+
120
+ # Create the directory first
121
+ os.makedirs(test_project_name)
122
+
123
+ # Try to create app with same name
124
+ result = run(
125
+ [
126
+ "jac",
127
+ "create_jac_app",
128
+ test_project_name
129
+ ],
130
+ capture_output=True,
131
+ text=True
132
+ )
133
+
134
+ # Should fail with non-zero exit code
135
+ self.assertNotEqual(result.returncode, 0)
136
+ self.assertIn(f"Directory '{test_project_name}' already exists", result.stderr)
137
+
138
+ finally:
139
+ os.chdir(original_cwd)
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: jac-client
3
+ Version: 0.1.0
4
+ Summary:
5
+ Author: Jason Mars
6
+ Author-email: jason@mars.ninja
7
+ Requires-Python: >=3.12.0,<4.0.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Classifier: Programming Language :: Python :: 3.14
12
+ Requires-Dist: jaclang (==0.8.10)
13
+ Description-Content-Type: text/markdown
14
+
15
+ # Jac Client
16
+
17
+ Build full-stack web applications with Jac - one language for frontend and backend.
18
+
19
+ Jac Client enables you to write React-like components, manage state, and build interactive UIs all in Jac. No need for separate frontend frameworks, HTTP clients, or complex build configurations.
20
+
21
+ ---
22
+
23
+ ## ✨ Features
24
+
25
+ - **Single Language**: Write frontend and backend in Jac
26
+ - **No HTTP Client**: Use `__jacSpawn()` instead of fetch/axios
27
+ - **Reactive State**: Built-in state management with `createState()`
28
+ - **Component-Based**: Build reusable UI components with JSX
29
+ - **Graph Database**: Built-in graph data model eliminates need for SQL/NoSQL
30
+ - **Type Safety**: Type checking across frontend and backend
31
+ - **Vite-Powered**: Optimized production bundles with Vite
32
+
33
+ ---
34
+
35
+ ## 🚀 Quick Start
36
+
37
+ ### Installation
38
+
39
+ ```bash
40
+ pip install jac-client
41
+ ```
42
+
43
+ ### Create a New App
44
+
45
+ ```bash
46
+ jac create_jac_app my-app
47
+ cd my-app
48
+ jac serve app.jac
49
+ ```
50
+
51
+ Visit `http://localhost:8000` to see your app!
52
+
53
+ ---
54
+
55
+ ## 📚 Documentation
56
+
57
+ For detailed guides and tutorials, see the **[docs folder](jac_client/docs/)**:
58
+
59
+ - **[Getting Started Guide](jac_client/docs/README.md)** - Complete beginner's guide
60
+ - **[Routing](jac_client/docs/routing.md)** - Multi-page applications with `initRouter()`
61
+ - **[Lifecycle Hooks](jac_client/docs/lifecycle-hooks.md)** - Using `onMount()` for initialization
62
+ - **[Advanced State](jac_client/docs/advanced-state.md)** - Managing complex state
63
+ - **[Imports](jac_client/docs/imports.md)** - Importing libraries, Jac files, and JavaScript modules
64
+
65
+ ---
66
+
67
+ ## 💡 Example
68
+
69
+ ```jac
70
+ cl {
71
+ let [count, setCount] = createState({"value": 0});
72
+
73
+ def Counter() -> any {
74
+ s = count();
75
+ return <div>
76
+ <h1>Count: {s.value}</h1>
77
+ <button onClick={lambda -> None {
78
+ setCount({"value": s.value + 1});
79
+ }}>
80
+ Increment
81
+ </button>
82
+ </div>;
83
+ }
84
+
85
+ def jac_app() -> any {
86
+ return Counter();
87
+ }
88
+ }
89
+ ```
90
+
91
+ ---
92
+
93
+ ## 🔧 Requirements
94
+
95
+ - Python: 3.12+
96
+ - Node.js: For npm and Vite
97
+ - Jac Language: `jaclang` (installed automatically)
98
+
99
+ ---
100
+
101
+ ## 🛠️ How It Works
102
+
103
+ Jac Client is a plugin that:
104
+ 1. Compiles your `.jac` client code to JavaScript
105
+ 2. Bundles dependencies with Vite for optimal performance
106
+ 3. Provides a runtime for reactive state and components
107
+ 4. Integrates seamlessly with Jac's backend graph operations
108
+
109
+ ---
110
+
111
+ ## 📖 Learn More
112
+
113
+ - **Full Documentation**: See [docs/](jac_client/docs/) for comprehensive guides
114
+ - **Examples**: Check `jac_client/examples/` for working examples
115
+ - **Issues**: Report bugs on [GitHub Issues](https://github.com/Jaseci-Labs/jaseci/issues)
116
+
117
+ ---
118
+
119
+ ## 📄 License
120
+
121
+ MIT License - see [LICENSE](../LICENSE) file.
122
+
123
+ ---
124
+
125
+ **Happy coding with Jac!** 🎉
126
+
@@ -0,0 +1,33 @@
1
+ jac_client/docs/README.md,sha256=LM1d3OphsarGMmUtcdCFzu5eXkQTThofZuscfnmORzY,15435
2
+ jac_client/docs/advanced-state.md,sha256=XpZwyXcFQNfcTdk5H9Cxcr-QhVWw8X9xcNIGpxXh13k,17107
3
+ jac_client/docs/imports.md,sha256=hBIZLsIZoMMCajwRlvgGtjYk2WqVz9GkPqHlHonAnzE,12468
4
+ jac_client/docs/lifecycle-hooks.md,sha256=Yg6Fuzgj5ouq0kA4KDU_x8-eFY95etyXP3ykAfoxkMk,12497
5
+ jac_client/docs/routing.md,sha256=kIwJmy9UzuxkKpj8yuHWNYHceEZ1Zi8H_c6bRwXEG2M,13661
6
+ jac_client/examples/little-x/app.jac,sha256=NueM8h35Bvf-hXL-kyeZ01-HAL7xZxUxrpHR99ASkhM,16760
7
+ jac_client/examples/little-x/package-lock.json,sha256=wlaWHbdT4gt8g6EIZLkgRqLOuoX4DgquNIYCXk46M6g,99176
8
+ jac_client/examples/little-x/package.json,sha256=XaXpijPuRDojT-yQFJwkaopDgqMiriepqEk0LsFQ-cU,521
9
+ jac_client/examples/little-x/submit-button.jac,sha256=ByyRpDDN49RxoF8k7TC0r1mgoKAwwdlpo6wiiTE7p_4,324
10
+ jac_client/examples/todo-app/README.md,sha256=eXQmqm63kuiNLF-FbHzE4oPQL26MiWu5_fvfc05X_iw,2101
11
+ jac_client/examples/todo-app/app.jac,sha256=HQML_uFKFIY03EnSeat-xQKafnfzj1lQzu46m9QeWLs,25628
12
+ jac_client/examples/todo-app/package-lock.json,sha256=56PSCXFx3qpwFpyyLf1sliNXobpvQPNfUDHYbOoRktE,31170
13
+ jac_client/examples/todo-app/package.json,sha256=gGOWdeCfPAl6g8pjGVIuPUuEm8h1XUTjF1r6MeuXiN4,413
14
+ jac_client/plugin/cli.py,sha256=4hB84MQ_3o2sWxWKIvmPURxnh_Kpt4iSrgoHHpFRRdA,10938
15
+ jac_client/plugin/client.py,sha256=76fqmTcfHBOXGs2hcsb3Wq09L5GW0r-5-9JGdvU_Nhs,1277
16
+ jac_client/plugin/client_runtime.jac,sha256=kjaODlNKjCbE-fXzkSYGN4k-SwmxsvBd4qQk9ZvYTGI,27507
17
+ jac_client/plugin/vite_client_bundle.py,sha256=1sQwtd9VgLd3cutidRR9DJMiiKahBlWzhWilhXPwmtA,18074
18
+ jac_client/tests/__init__.py,sha256=zleq_UtH4HBbp9SSkkqtaLd1tvm5F3QfXHEffXpxxQo,37
19
+ jac_client/tests/fixtures/button.jac,sha256=8xLhhX7UpiRdzO9BLC1XwhejiKMEi50VlPFSjJP0XR8,109
20
+ jac_client/tests/fixtures/client_app.jac,sha256=ReEvwsPHEh56RfSmW_KCM9sk6jjr5QnSENMUJHZfMVs,445
21
+ jac_client/tests/fixtures/client_app_with_antd.jac,sha256=e-BK4TVlw8OKiCxIS0tH1-oJkWNEon-eMaJXvBvX39M,399
22
+ jac_client/tests/fixtures/js_import.jac,sha256=GmAMLEFTp-CfoQ4G2JmFpD4boKpYh8JTC9LZRX5CieM,721
23
+ jac_client/tests/fixtures/package-lock.json,sha256=RKNoyMoGXx3IOm3B5d1Kt0vrgMac9intCLXGew51AAQ,19358
24
+ jac_client/tests/fixtures/package.json,sha256=s5Ltvbh1MQGeZZyyNJdqhoA21VO5F7scBcVPlgHpF3c,278
25
+ jac_client/tests/fixtures/relative_import.jac,sha256=3ZDq-eg4BIdULklet-Enic-AVRFVnAbBkQwOOmfFbaM,190
26
+ jac_client/tests/fixtures/test_fragments_spread.jac,sha256=z8Hs6N7HV8dE7jrW0NZtUt7Tbuo-bWkYBW4O8N7A-Rw,964
27
+ jac_client/tests/fixtures/utils.js,sha256=lrcZ9yUEb4QrpUpUp0gWRvISFui9_v96rWPN-btllmU,413
28
+ jac_client/tests/test_cl.py,sha256=4Ulr-5plEX3PDuVnIaMfFUcfQj3l0YrWd5ExNybpnIo,15398
29
+ jac_client/tests/test_create_jac_app.py,sha256=UXDFYAjYHoRbNSfT0pfwVqXZ3h0cBMQ_nXevB0BpDtI,5518
30
+ jac_client-0.1.0.dist-info/METADATA,sha256=mtXw8sK4Ac3Hc1IWp6bS9T9ImiW07l5Uk24UDZGWl1I,3202
31
+ jac_client-0.1.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
32
+ jac_client-0.1.0.dist-info/entry_points.txt,sha256=WxzPDwDUGAvQyJ_RkIOSk3cJgJChESQGP839Kb70_vo,92
33
+ jac_client-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.2.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,4 @@
1
+ [jac]
2
+ create_jac_app=jac_client.plugin.cli:JacCmd
3
+ serve=jac_client.plugin.client:JacClient
4
+