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,22 @@
1
+ {
2
+ "name": "todo-app",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "scripts": {
6
+ "build": "vite build",
7
+ "dev": "vite dev",
8
+ "preview": "vite preview"
9
+ },
10
+ "keywords": [],
11
+ "author": "",
12
+ "license": "ISC",
13
+ "description": "Jac application: todo-app",
14
+ "type": "module",
15
+ "devDependencies": {
16
+ "vite": "^5.0.0"
17
+ },
18
+ "dependencies": {
19
+ "react": "^18.2.0",
20
+ "react-dom": "^18.2.0"
21
+ }
22
+ }
@@ -0,0 +1,328 @@
1
+ """Command line interface tool for the Jac Client."""
2
+
3
+ import json
4
+ import os
5
+ import re
6
+ import subprocess
7
+ import sys
8
+
9
+ from jaclang.cli.cmdreg import cmd_registry
10
+ from jaclang.runtimelib.machine import hookimpl
11
+
12
+
13
+ class JacCmd:
14
+ """Jac CLI."""
15
+
16
+ @staticmethod
17
+ @hookimpl
18
+ def create_cmd() -> None:
19
+ """Create Jac CLI cmds."""
20
+
21
+ @cmd_registry.register
22
+ def create_jac_app(name: str) -> None:
23
+ """Create a new Jac application with npm and Vite setup.
24
+
25
+ Bootstraps a new Jac project by creating a temporary directory, initializing
26
+ npm, installing Vite, and setting up the basic project structure.
27
+
28
+ Args:
29
+ name: Name of the project to create
30
+
31
+ Examples:
32
+ jac create_jac_app my-app
33
+ jac create_jac_app my-jac-project
34
+ """
35
+ if not name:
36
+ print(
37
+ "Error: Project name is required. Use --name=your-project-name",
38
+ file=sys.stderr,
39
+ )
40
+ exit(1)
41
+
42
+ # Validate project name (basic npm package name validation)
43
+ if not re.match(r"^[a-zA-Z0-9_-]+$", name):
44
+ print(
45
+ "Error: Project name must contain only letters, numbers, hyphens, and underscores",
46
+ file=sys.stderr,
47
+ )
48
+ exit(1)
49
+
50
+ print(f"Creating new Jac application: {name}")
51
+
52
+ # Create project directory in current working directory
53
+ project_path = os.path.join(os.getcwd(), name)
54
+
55
+ if os.path.exists(project_path):
56
+ print(
57
+ f"Error: Directory '{name}' already exists in current location",
58
+ file=sys.stderr,
59
+ )
60
+ exit(1)
61
+
62
+ os.makedirs(project_path, exist_ok=True)
63
+
64
+ try:
65
+ # Change to project directory
66
+ original_cwd = os.getcwd()
67
+ os.chdir(project_path)
68
+
69
+ # Initialize npm package
70
+ print("Initializing npm package...")
71
+ npm_init_cmd = ["npm", "init", "-y"]
72
+ subprocess.run(npm_init_cmd, capture_output=True, text=True, check=True)
73
+
74
+ # Read the generated package.json
75
+ package_json_path = os.path.join(project_path, "package.json")
76
+ with open(package_json_path, "r") as f:
77
+ package_data = json.load(f)
78
+
79
+ # create temp folder
80
+ temp_folder = os.path.join(project_path, "temp")
81
+ os.makedirs(temp_folder, exist_ok=True)
82
+
83
+ # create static/client/js folder
84
+ client_js_folder = os.path.join(project_path, "static", "client", "js")
85
+ os.makedirs(client_js_folder, exist_ok=True)
86
+
87
+ # Update package.json with Jac-specific configuration
88
+ package_data.update(
89
+ {
90
+ "name": name,
91
+ "description": f"Jac application: {name}",
92
+ "type": "module",
93
+ "scripts": {
94
+ "build": "vite build",
95
+ "dev": "vite dev",
96
+ "preview": "vite preview",
97
+ },
98
+ "devDependencies": {"vite": "^5.0.0"},
99
+ "dependencies": {"react": "^18.2.0", "react-dom": "^18.2.0"},
100
+ }
101
+ )
102
+
103
+ # Write updated package.json
104
+ with open(package_json_path, "w") as f:
105
+ json.dump(package_data, f, indent=2)
106
+
107
+ print("Installing Vite...")
108
+ # Install Vite
109
+ npm_install_cmd = ["npm", "install"]
110
+ subprocess.run(
111
+ npm_install_cmd, capture_output=True, text=True, check=True
112
+ )
113
+
114
+ # Create basic project structure
115
+ print("Setting up project structure...")
116
+
117
+ # Create a basic Jac file
118
+ main_jac_content = """
119
+ # Pages
120
+ cl def HomeView() -> any {
121
+ return <div
122
+ style={{
123
+ "minHeight": "100vh",
124
+ "fontFamily": "-apple-system, BlinkMacSystemFont, sans-serif"
125
+ }}>
126
+ <main
127
+ style={{
128
+ "maxWidth": "1200px",
129
+ "margin": "0 auto",
130
+ "padding": "60px 40px"
131
+ }}>
132
+ <div
133
+ style={{
134
+ "textAlign": "center",
135
+ "marginBottom": "80px"
136
+ }}>
137
+ <h1
138
+ style={{
139
+ "fontSize": "56px",
140
+ "marginBottom": "20px"
141
+ }}>
142
+ Welcome to
143
+ <span style={{"color": "#007bff"}}>OneLang</span>
144
+ </h1>
145
+ <p
146
+ style={{
147
+ "fontSize": "20px",
148
+ "color": "#666"
149
+ }}>
150
+ One Language. One Stack. Zero Friction.
151
+ </p>
152
+ </div>
153
+
154
+ <div
155
+ style={{
156
+ "display": "grid",
157
+ "gridTemplateColumns": "repeat(2, 1fr)",
158
+ "gap": "24px",
159
+ "marginBottom": "60px"
160
+ }}>
161
+ <a
162
+ href="https://docs.jaseci.org"
163
+ target="_blank"
164
+ style={{
165
+ "padding": "32px",
166
+ "backgroundColor": "white",
167
+ "border": "1px solid #eaeaea",
168
+ "borderRadius": "8px",
169
+ "textDecoration": "none",
170
+ "color": "#000"
171
+ }}>
172
+ <h3
173
+ style={{
174
+ "marginTop": "0",
175
+ "marginBottom": "12px"
176
+ }}>📖 Documentation</h3>
177
+ <p style={{"color": "#666", "margin": "0"}}>
178
+ Learn how to build with OneLang
179
+ </p>
180
+ </a>
181
+ <a
182
+ href="https://docs.jaseci.org/learn"
183
+ target="_blank"
184
+ style={{
185
+ "padding": "32px",
186
+ "backgroundColor": "white",
187
+ "border": "1px solid #eaeaea",
188
+ "borderRadius": "8px",
189
+ "textDecoration": "none",
190
+ "color": "#000"
191
+ }}>
192
+ <h3
193
+ style={{
194
+ "marginTop": "0",
195
+ "marginBottom": "12px"
196
+ }}>🎓 Learn</h3>
197
+ <p style={{"color": "#666", "margin": "0"}}>
198
+ Tutorials and guides
199
+ </p>
200
+ </a>
201
+ <a
202
+ href="/examples"
203
+ style={{
204
+ "padding": "32px",
205
+ "backgroundColor": "white",
206
+ "border": "1px solid #eaeaea",
207
+ "borderRadius": "8px",
208
+ "textDecoration": "none",
209
+ "color": "#000"
210
+ }}>
211
+ <h3
212
+ style={{
213
+ "marginTop": "0",
214
+ "marginBottom": "12px"
215
+ }}>💡 Examples</h3>
216
+ <p style={{"color": "#666", "margin": "0"}}>
217
+ Sample applications
218
+ </p>
219
+ </a>
220
+ <a
221
+ href="https://github.com/Jaseci-Labs/jaseci"
222
+ target="_blank"
223
+ style={{
224
+ "padding": "32px",
225
+ "backgroundColor": "white",
226
+ "border": "1px solid #eaeaea",
227
+ "borderRadius": "8px",
228
+ "textDecoration": "none",
229
+ "color": "#000"
230
+ }}>
231
+ <h3
232
+ style={{
233
+ "marginTop": "0",
234
+ "marginBottom": "12px"
235
+ }}>🔧 Community</h3>
236
+ <p style={{"color": "#666", "margin": "0"}}>
237
+ GitHub repository
238
+ </p>
239
+ </a>
240
+ </div>
241
+
242
+ <footer
243
+ style={{
244
+ "borderTop": "1px solid #eaeaea",
245
+ "paddingTop": "40px",
246
+ "textAlign": "center",
247
+ "color": "#999"
248
+ }}>
249
+ <p>
250
+ Get started by editing
251
+ <code
252
+ style={{
253
+ "backgroundColor": "#f5f5f5",
254
+ "padding": "2px 6px",
255
+ "borderRadius": "3px"
256
+ }}>app.jac</code>
257
+ </p>
258
+ </footer>
259
+ </main>
260
+ </div>;
261
+ }
262
+
263
+
264
+ # Main App component with declarative router
265
+ cl def App() -> any {
266
+
267
+ home_route = {
268
+ "path": "/",
269
+ "component": lambda -> any { return HomeView(); },
270
+ "guard": None
271
+ };
272
+
273
+ routes = [home_route];
274
+ router = initRouter(routes, "/");
275
+
276
+ # add all the wrapper components here
277
+ return <div class="app-container">
278
+ {router.render()}
279
+ </div>;
280
+ }
281
+
282
+ # Main SPA entry point - simplified with reactive routing
283
+ cl def jac_app() -> any {
284
+ return App();
285
+ }
286
+ """
287
+
288
+ with open(os.path.join(project_path, "app.jac"), "w") as f:
289
+ f.write(main_jac_content)
290
+
291
+ # Create README.md
292
+ readme_content = f"""# {name}
293
+
294
+ ## Running Jac Code
295
+
296
+ To run your Jac code, use the Jac CLI:
297
+
298
+ ```bash
299
+ jac serve app.jac
300
+ ```
301
+
302
+ Happy coding with Jac!
303
+ """
304
+
305
+ with open(os.path.join(project_path, "README.md"), "w") as f:
306
+ f.write(readme_content)
307
+
308
+ # Return to original directory
309
+ os.chdir(original_cwd)
310
+
311
+ print(f"✅ Successfully created Jac application '{name}'!")
312
+ print(f"📁 Project location: {os.path.abspath(project_path)}")
313
+ print("\nNext steps:")
314
+ print(f" cd {name}")
315
+ print(" jac serve app.jac")
316
+
317
+ except subprocess.CalledProcessError as e:
318
+ # Return to original directory on error
319
+ os.chdir(original_cwd)
320
+ print(f"Error running npm command: {e}", file=sys.stderr)
321
+ print(f"Command output: {e.stdout}", file=sys.stderr)
322
+ print(f"Command error: {e.stderr}", file=sys.stderr)
323
+ exit(1)
324
+ except Exception as e:
325
+ # Return to original directory on error
326
+ os.chdir(original_cwd)
327
+ print(f"Error creating project: {e}", file=sys.stderr)
328
+ exit(1)
@@ -0,0 +1,41 @@
1
+ import types
2
+ from pathlib import Path
3
+
4
+ from jaclang.runtimelib.client_bundle import ClientBundle
5
+ from jaclang.runtimelib.machine import (
6
+ JacMachine as Jac,
7
+ hookimpl,
8
+ )
9
+
10
+ from .vite_client_bundle import ViteClientBundleBuilder
11
+
12
+
13
+ class JacClient:
14
+ """Jac Client."""
15
+
16
+ @staticmethod
17
+ @hookimpl
18
+ def get_client_bundle_builder() -> ViteClientBundleBuilder:
19
+ """Get the client bundle builder instance."""
20
+ base_path = Path(Jac.base_path_dir)
21
+ package_json_path = base_path / "package.json"
22
+ output_dir = base_path / "static" / "client" / "js"
23
+ # Use the plugin's client_runtime.jac file
24
+ runtime_path = Path(__file__).with_name("client_runtime.jac")
25
+ print(f"Runtime path: {runtime_path}")
26
+ return ViteClientBundleBuilder(
27
+ runtime_path=runtime_path,
28
+ vite_package_json=package_json_path,
29
+ vite_output_dir=output_dir,
30
+ vite_minify=False,
31
+ )
32
+
33
+ @staticmethod
34
+ @hookimpl
35
+ def build_client_bundle(
36
+ module: types.ModuleType,
37
+ force: bool = False,
38
+ ) -> ClientBundle:
39
+ """Build a client bundle for the supplied module."""
40
+ builder = JacClient.get_client_bundle_builder()
41
+ return builder.build(module, force=force)