jac-client 0.2.5__tar.gz → 0.2.7__tar.gz
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-0.2.5 → jac_client-0.2.7}/PKG-INFO +16 -7
- {jac_client-0.2.5 → jac_client-0.2.7}/README.md +14 -5
- jac_client-0.2.7/jac_client/examples/all-in-one/src/app.jac +573 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/components/CategoryFilter.jac +35 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/components/Header.jac +13 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/components/ProfitOverview.jac +50 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/components/Summary.jac +53 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/components/TransactionForm.jac +158 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/components/TransactionItem.jac +55 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/components/TransactionList.jac +37 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/components/navigation.jac +132 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/constants/categories.jac +37 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/constants/clients.jac +13 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/context/BudgetContext.jac +28 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/hooks/useBudget.jac +116 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/hooks/useLocalStorage.jac +36 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/pages/BudgetPlanner.cl.jac +70 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/pages/BudgetPlanner.jac +126 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/pages/FeaturesTest.cl.jac +552 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/pages/FeaturesTest.jac +126 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/pages/LandingPage.jac +101 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/pages/loginPage.jac +132 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/pages/nestedDemo.jac +61 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/pages/notFound.jac +24 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/pages/signupPage.jac +133 -0
- jac_client-0.2.7/jac_client/examples/all-in-one/src/utils/formatters.jac +52 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/asset-serving/css-with-image/src/app.jac +3 -3
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/asset-serving/image-asset/src/app.jac +3 -3
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/asset-serving/import-alias/src/app.jac +3 -3
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/basic/src/app.jac +3 -3
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/basic-auth/src/app.jac +31 -37
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/basic-auth-with-router/src/app.jac +16 -16
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/basic-full-stack/src/app.jac +24 -30
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/css-styling/js-styling/src/app.jac +5 -5
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/css-styling/material-ui/src/app.jac +5 -5
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/css-styling/pure-css/src/app.jac +5 -5
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/css-styling/sass-example/src/app.jac +5 -5
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/css-styling/styled-components/src/app.jac +5 -5
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/css-styling/tailwind-example/src/app.jac +5 -5
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/full-stack-with-auth/src/app.jac +16 -16
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/ts-support/src/app.jac +4 -4
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/with-router/src/app.jac +4 -4
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/cli.jac +155 -203
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/client_runtime.cl.jac +5 -1
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/impl/client.impl.jac +74 -12
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/plugin_config.jac +11 -11
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/compiler.jac +2 -1
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/impl/babel_processor.impl.jac +22 -17
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/impl/compiler.impl.jac +57 -18
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/impl/vite_bundler.impl.jac +66 -102
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/package_installer.jac +1 -1
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/vite_bundler.jac +1 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/tests/conftest.py +10 -8
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/tests/fixtures/spawn_test/app.jac +15 -18
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/tests/fixtures/with-ts/app.jac +4 -4
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/tests/test_cli.py +99 -45
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/tests/test_it.py +290 -79
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client.egg-info/PKG-INFO +16 -7
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client.egg-info/SOURCES.txt +23 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client.egg-info/requires.txt +1 -1
- {jac_client-0.2.5 → jac_client-0.2.7}/pyproject.toml +3 -3
- jac_client-0.2.5/jac_client/examples/all-in-one/src/app.jac +0 -841
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/all-in-one/assets/workers/worker.py +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/all-in-one/src/button.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/all-in-one/src/components/button.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/little-x/src/app.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/little-x/src/submit-button.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/nested-folders/nested-advance/src/ButtonRoot.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/nested-folders/nested-advance/src/app.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/nested-folders/nested-advance/src/level1/ButtonSecondL.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/nested-folders/nested-advance/src/level1/Card.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/nested-folders/nested-advance/src/level1/level2/ButtonThirdL.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/nested-folders/nested-basic/src/app.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/nested-folders/nested-basic/src/button.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/examples/nested-folders/nested-basic/src/components/button.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/client.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/impl/client_runtime.impl.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/impl/vite_client_bundle.impl.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/__init__.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/asset_processor.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/babel_processor.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/config_loader.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/impl/asset_processor.impl.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/impl/config_loader.impl.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/impl/import_processor.impl.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/impl/jac_to_js.impl.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/impl/package_installer.impl.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/import_processor.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/src/jac_to_js.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/plugin/vite_client_bundle.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/tests/__init__.py +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/tests/fixtures/basic-app/app.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/tests/fixtures/cl_file/app.cl.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/tests/fixtures/cl_file/app.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/tests/fixtures/client_app_with_antd/app.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/tests/fixtures/js_import/app.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/tests/fixtures/relative_import/app.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/tests/fixtures/relative_import/button.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client/tests/fixtures/test_fragments_spread/app.jac +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client.egg-info/dependency_links.txt +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client.egg-info/entry_points.txt +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/jac_client.egg-info/top_level.txt +0 -0
- {jac_client-0.2.5 → jac_client-0.2.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jac-client
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: Build full-stack web applications with Jac - one language for frontend and backend.
|
|
5
5
|
Author-email: Jason Mars <jason@mars.ninja>
|
|
6
6
|
Maintainer-email: Jason Mars <jason@mars.ninja>
|
|
@@ -11,7 +11,7 @@ Project-URL: Documentation, https://jac-lang.org
|
|
|
11
11
|
Keywords: jac,jaclang,jaseci,frontend,full-stack,web-development
|
|
12
12
|
Requires-Python: >=3.12
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
|
-
Requires-Dist: jaclang==0.9.
|
|
14
|
+
Requires-Dist: jaclang==0.9.7
|
|
15
15
|
Provides-Extra: dev
|
|
16
16
|
Requires-Dist: python-dotenv==1.0.1; extra == "dev"
|
|
17
17
|
Requires-Dist: pytest==8.3.5; extra == "dev"
|
|
@@ -28,7 +28,7 @@ Jac Client enables you to write React-like components, manage state, and build i
|
|
|
28
28
|
|
|
29
29
|
- **Single Language**: Write frontend and backend in Jac
|
|
30
30
|
- **No HTTP Client**: Use `jacSpawn()` instead of fetch/axios
|
|
31
|
-
- **React Hooks**: Use standard React `useState` and `useEffect` hooks
|
|
31
|
+
- **React Hooks**: Use standard React `useState` and `useEffect` hooks (useState is auto-injected when using `has` variables)
|
|
32
32
|
- **Component-Based**: Build reusable UI components with JSX
|
|
33
33
|
- **Graph Database**: Built-in graph data model eliminates need for SQL/NoSQL
|
|
34
34
|
- **Type Safety**: Type checking across frontend and backend
|
|
@@ -49,10 +49,12 @@ pip install jac-client
|
|
|
49
49
|
```bash
|
|
50
50
|
jac create --cl my-app
|
|
51
51
|
cd my-app
|
|
52
|
-
jac
|
|
52
|
+
jac start src/app.jac
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
Visit `http://localhost:8000
|
|
55
|
+
Visit `http://localhost:8000` to see your app! (The `app` component is served at the root by default.)
|
|
56
|
+
|
|
57
|
+
You can also access the app at `http://localhost:8000/cl/app`.
|
|
56
58
|
|
|
57
59
|
> **Note**: The `--cl` flag creates a client-side project with an organized folder structure. Without `--cl`, `jac create` creates a standard Jac project.
|
|
58
60
|
|
|
@@ -75,10 +77,13 @@ For detailed guides and tutorials, see the **[docs folder](jac_client/docs/)**:
|
|
|
75
77
|
### Simple Counter with React Hooks
|
|
76
78
|
|
|
77
79
|
```jac
|
|
78
|
-
|
|
80
|
+
# Note: useState is auto-injected when using has variables in cl blocks
|
|
81
|
+
# Only useEffect needs explicit import
|
|
82
|
+
cl import from react { useEffect }
|
|
79
83
|
|
|
80
84
|
cl {
|
|
81
85
|
def Counter() -> any {
|
|
86
|
+
# useState is automatically available - no import needed!
|
|
82
87
|
[count, setCount] = useState(0);
|
|
83
88
|
|
|
84
89
|
useEffect(lambda -> None {
|
|
@@ -101,10 +106,13 @@ cl {
|
|
|
101
106
|
}
|
|
102
107
|
```
|
|
103
108
|
|
|
109
|
+
> **Note:** When using `has` variables in `cl {}` blocks or `.cl.jac` files, the `useState` import is automatically injected. You only need to explicitly import other hooks like `useEffect`.
|
|
110
|
+
|
|
104
111
|
### Full-Stack Todo App
|
|
105
112
|
|
|
106
113
|
```jac
|
|
107
|
-
|
|
114
|
+
# useState is auto-injected, only import useEffect
|
|
115
|
+
cl import from react { useEffect }
|
|
108
116
|
cl import from '@jac-client/utils' { jacSpawn }
|
|
109
117
|
|
|
110
118
|
# Backend: Jac nodes and walkers
|
|
@@ -130,6 +138,7 @@ walker read_todos {
|
|
|
130
138
|
# Frontend: React component
|
|
131
139
|
cl {
|
|
132
140
|
def app() -> any {
|
|
141
|
+
# useState is automatically available - no import needed!
|
|
133
142
|
[todos, setTodos] = useState([]);
|
|
134
143
|
|
|
135
144
|
useEffect(lambda -> None {
|
|
@@ -10,7 +10,7 @@ Jac Client enables you to write React-like components, manage state, and build i
|
|
|
10
10
|
|
|
11
11
|
- **Single Language**: Write frontend and backend in Jac
|
|
12
12
|
- **No HTTP Client**: Use `jacSpawn()` instead of fetch/axios
|
|
13
|
-
- **React Hooks**: Use standard React `useState` and `useEffect` hooks
|
|
13
|
+
- **React Hooks**: Use standard React `useState` and `useEffect` hooks (useState is auto-injected when using `has` variables)
|
|
14
14
|
- **Component-Based**: Build reusable UI components with JSX
|
|
15
15
|
- **Graph Database**: Built-in graph data model eliminates need for SQL/NoSQL
|
|
16
16
|
- **Type Safety**: Type checking across frontend and backend
|
|
@@ -31,10 +31,12 @@ pip install jac-client
|
|
|
31
31
|
```bash
|
|
32
32
|
jac create --cl my-app
|
|
33
33
|
cd my-app
|
|
34
|
-
jac
|
|
34
|
+
jac start src/app.jac
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
Visit `http://localhost:8000
|
|
37
|
+
Visit `http://localhost:8000` to see your app! (The `app` component is served at the root by default.)
|
|
38
|
+
|
|
39
|
+
You can also access the app at `http://localhost:8000/cl/app`.
|
|
38
40
|
|
|
39
41
|
> **Note**: The `--cl` flag creates a client-side project with an organized folder structure. Without `--cl`, `jac create` creates a standard Jac project.
|
|
40
42
|
|
|
@@ -57,10 +59,13 @@ For detailed guides and tutorials, see the **[docs folder](jac_client/docs/)**:
|
|
|
57
59
|
### Simple Counter with React Hooks
|
|
58
60
|
|
|
59
61
|
```jac
|
|
60
|
-
|
|
62
|
+
# Note: useState is auto-injected when using has variables in cl blocks
|
|
63
|
+
# Only useEffect needs explicit import
|
|
64
|
+
cl import from react { useEffect }
|
|
61
65
|
|
|
62
66
|
cl {
|
|
63
67
|
def Counter() -> any {
|
|
68
|
+
# useState is automatically available - no import needed!
|
|
64
69
|
[count, setCount] = useState(0);
|
|
65
70
|
|
|
66
71
|
useEffect(lambda -> None {
|
|
@@ -83,10 +88,13 @@ cl {
|
|
|
83
88
|
}
|
|
84
89
|
```
|
|
85
90
|
|
|
91
|
+
> **Note:** When using `has` variables in `cl {}` blocks or `.cl.jac` files, the `useState` import is automatically injected. You only need to explicitly import other hooks like `useEffect`.
|
|
92
|
+
|
|
86
93
|
### Full-Stack Todo App
|
|
87
94
|
|
|
88
95
|
```jac
|
|
89
|
-
|
|
96
|
+
# useState is auto-injected, only import useEffect
|
|
97
|
+
cl import from react { useEffect }
|
|
90
98
|
cl import from '@jac-client/utils' { jacSpawn }
|
|
91
99
|
|
|
92
100
|
# Backend: Jac nodes and walkers
|
|
@@ -112,6 +120,7 @@ walker read_todos {
|
|
|
112
120
|
# Frontend: React component
|
|
113
121
|
cl {
|
|
114
122
|
def app() -> any {
|
|
123
|
+
# useState is automatically available - no import needed!
|
|
115
124
|
[todos, setTodos] = useState([]);
|
|
116
125
|
|
|
117
126
|
useEffect(lambda -> None {
|
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
import from datetime { datetime, timedelta }
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Basic backend walkers
|
|
5
|
+
#
|
|
6
|
+
node Todo {
|
|
7
|
+
has text: str,
|
|
8
|
+
done: bool = False;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
walker create_todo {
|
|
12
|
+
has text: str;
|
|
13
|
+
|
|
14
|
+
can create with `root entry {
|
|
15
|
+
new_todo = here ++> Todo(text=self.text);
|
|
16
|
+
report new_todo ;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
walker ping_server {
|
|
21
|
+
can ping with `root entry {
|
|
22
|
+
report "pong from backend!" ;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
walker get_server_message {
|
|
27
|
+
can info with `root entry {
|
|
28
|
+
report "hello from a basic walker!" ;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# Features Test Page - Backend Logic
|
|
35
|
+
# This file is intentionally kept empty to demonstrate the separation of concerns
|
|
36
|
+
# where UI logic resides in .cl.jac files and backend walker logic in app.jac
|
|
37
|
+
|
|
38
|
+
# All walker implementations for this feature are in src/app.jac
|
|
39
|
+
# This demonstrates that you can have separate .jac files for different purposes
|
|
40
|
+
# Features Test - Backend Walkers
|
|
41
|
+
# This file demonstrates walker functionality for testing various JAC features
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Node definition for storing test data
|
|
45
|
+
node TestData {
|
|
46
|
+
has message: str;
|
|
47
|
+
has count: int = 0;
|
|
48
|
+
has created_at: str = "";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# Walker: Create test data
|
|
52
|
+
walker create_test_data {
|
|
53
|
+
has message: str;
|
|
54
|
+
|
|
55
|
+
can create with `root entry {
|
|
56
|
+
new_data = here ++> TestData(
|
|
57
|
+
message=self.message,
|
|
58
|
+
count=1,
|
|
59
|
+
created_at=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
60
|
+
);
|
|
61
|
+
report new_data;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Walker: Read all test data
|
|
66
|
+
walker read_test_data {
|
|
67
|
+
can read with `root entry {
|
|
68
|
+
visit [-->(`?TestData)];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
can report_data with exit {
|
|
72
|
+
report here;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# Walker: Update test data
|
|
77
|
+
walker update_test_data {
|
|
78
|
+
has new_message: str;
|
|
79
|
+
|
|
80
|
+
can update with TestData entry {
|
|
81
|
+
here.message = self.new_message;
|
|
82
|
+
here.count = here.count + 1;
|
|
83
|
+
report here;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Walker: Delete test data
|
|
88
|
+
walker delete_test_data {
|
|
89
|
+
can delete with TestData entry {
|
|
90
|
+
del here;
|
|
91
|
+
report {"status": "deleted"};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
# Walker: String manipulation test
|
|
96
|
+
walker test_string_methods {
|
|
97
|
+
has input_text: str;
|
|
98
|
+
|
|
99
|
+
can process with `root entry {
|
|
100
|
+
result = {
|
|
101
|
+
"original": self.input_text,
|
|
102
|
+
"uppercase": self.input_text.upper(),
|
|
103
|
+
"lowercase": self.input_text.lower(),
|
|
104
|
+
"capitalized": self.input_text.capitalize(),
|
|
105
|
+
"reversed": self.input_text[::-1],
|
|
106
|
+
"length": len(self.input_text),
|
|
107
|
+
"words": self.input_text.split(),
|
|
108
|
+
"trimmed": self.input_text.strip(),
|
|
109
|
+
"replaced": self.input_text.replace("test", "demo")
|
|
110
|
+
};
|
|
111
|
+
report result;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# Walker: Array/List operations test
|
|
116
|
+
walker test_list_operations {
|
|
117
|
+
has numbers: list;
|
|
118
|
+
|
|
119
|
+
can process with `root entry {
|
|
120
|
+
result = {
|
|
121
|
+
"original": self.numbers,
|
|
122
|
+
"sorted": sorted(self.numbers),
|
|
123
|
+
"reversed": list(reversed(self.numbers)),
|
|
124
|
+
"sum": sum(self.numbers),
|
|
125
|
+
"max": max(self.numbers) if len(self.numbers) > 0 else 0,
|
|
126
|
+
"min": min(self.numbers) if len(self.numbers) > 0 else 0,
|
|
127
|
+
"length": len(self.numbers),
|
|
128
|
+
"doubled": [x * 2 for x in self.numbers]
|
|
129
|
+
};
|
|
130
|
+
report result;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
# Walker: Complex data processing
|
|
135
|
+
walker process_complex_data {
|
|
136
|
+
has items: list;
|
|
137
|
+
|
|
138
|
+
can process with `root entry {
|
|
139
|
+
processed = [];
|
|
140
|
+
for item in self.items {
|
|
141
|
+
processed.append({
|
|
142
|
+
"id": item.get("id", 0),
|
|
143
|
+
"name": item.get("name", "").upper(),
|
|
144
|
+
"value": item.get("value", 0) * 2,
|
|
145
|
+
"processed_at": datetime.now().strftime("%H:%M:%S")
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
result = {
|
|
150
|
+
"original_count": len(self.items),
|
|
151
|
+
"processed_count": len(processed),
|
|
152
|
+
"items": processed,
|
|
153
|
+
"total_value": sum([p["value"] for p in processed])
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
report result;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
#
|
|
162
|
+
# Combined example: auth + routing + CSS styling + asset serving + nested folder imports
|
|
163
|
+
#
|
|
164
|
+
cl import from react { useEffect, useRef }
|
|
165
|
+
cl import from "@jac-client/utils" {
|
|
166
|
+
Router,
|
|
167
|
+
Routes,
|
|
168
|
+
Route,
|
|
169
|
+
Link,
|
|
170
|
+
useNavigate,
|
|
171
|
+
Navigate,
|
|
172
|
+
jacIsLoggedIn
|
|
173
|
+
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
# Pure CSS + asset-in-CSS example
|
|
177
|
+
cl import ".styles.css";
|
|
178
|
+
|
|
179
|
+
# Login Page
|
|
180
|
+
cl import from .pages.loginPage { LoginPage }
|
|
181
|
+
|
|
182
|
+
# Signup Page
|
|
183
|
+
cl import from .pages.signupPage { SignupPage }
|
|
184
|
+
|
|
185
|
+
# Simple 404 page
|
|
186
|
+
cl import from .pages.notFound { NotFound }
|
|
187
|
+
|
|
188
|
+
# Navigation component with active link styling and auth
|
|
189
|
+
cl import from .components.navigation { Navigation }
|
|
190
|
+
|
|
191
|
+
# Page showing nested imports from different folders
|
|
192
|
+
cl import from .pages.nestedDemo { NestedImportsDemo }
|
|
193
|
+
|
|
194
|
+
cl import from .pages.FeaturesTest { FeaturesTest }
|
|
195
|
+
|
|
196
|
+
cl import from .pages.LandingPage { LandingPage }
|
|
197
|
+
|
|
198
|
+
cl import from .pages.BudgetPlanner { BudgetPlanner }
|
|
199
|
+
|
|
200
|
+
# Context provider
|
|
201
|
+
cl import from .context.BudgetContext { BudgetProvider }
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
# TypeScript component import
|
|
206
|
+
cl import from ".components/Card.tsx" { Card }
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# Main app wrapped in Router (same API as with-router/ example)
|
|
210
|
+
cl {
|
|
211
|
+
def:pub HomePage -> any {
|
|
212
|
+
# Check if user is logged in, redirect if not
|
|
213
|
+
if not jacIsLoggedIn() {
|
|
214
|
+
return <Navigate to="/login" />;
|
|
215
|
+
}
|
|
216
|
+
has count: int = 0;
|
|
217
|
+
has pingResult: str = "";
|
|
218
|
+
has serverMessage: str = "";
|
|
219
|
+
has lastTodoMessage: str = "";
|
|
220
|
+
|
|
221
|
+
useEffect(
|
|
222
|
+
lambda -> None{ console.log("Home count changed: ", count);} , [count]
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
# Call simple backend walkers
|
|
226
|
+
async def handlePing -> None {
|
|
227
|
+
result = root spawn ping_server();
|
|
228
|
+
if result.reports and result.reports.length > 0 {
|
|
229
|
+
pingResult = result.reports[0][0];
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async def loadServerMessage -> None {
|
|
234
|
+
result = root spawn get_server_message();
|
|
235
|
+
if result.reports and result.reports.length > 0 {
|
|
236
|
+
serverMessage = result.reports[0][0];
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
# Create a sample Todo node in the graph with a hardcoded payload
|
|
241
|
+
async def handleCreateSampleTodo -> None {
|
|
242
|
+
result = root spawn create_todo(text="Sample todo from all-in-one app");
|
|
243
|
+
if result.reports and result.reports.length > 0 {
|
|
244
|
+
todo = result.reports[0][0];
|
|
245
|
+
lastTodoMessage = "Created Todo: " + todo.text;
|
|
246
|
+
console.log("Created Todo node:", todo);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
useEffect(lambda -> None{ loadServerMessage();} , []);
|
|
251
|
+
|
|
252
|
+
# Initialize a Web Worker and handle message-based communication
|
|
253
|
+
workerRef = useRef(None);
|
|
254
|
+
has message: str = "";
|
|
255
|
+
|
|
256
|
+
useEffect(lambda -> None {
|
|
257
|
+
workerRef.current = Reflect.construct(Worker, ["/workers/worker.js"]);
|
|
258
|
+
workerRef.current.onmessage = lambda event: any -> None {
|
|
259
|
+
console.log("Message received from worker:", event.data);
|
|
260
|
+
message = event.data;
|
|
261
|
+
};
|
|
262
|
+
return (lambda -> None {
|
|
263
|
+
workerRef.current.terminate();
|
|
264
|
+
});
|
|
265
|
+
}, []);
|
|
266
|
+
handleClick = lambda -> None {
|
|
267
|
+
workerRef.current.postMessage("");
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
return <div
|
|
271
|
+
style={{
|
|
272
|
+
"padding": "2rem",
|
|
273
|
+
"fontFamily": "system-ui, -apple-system, sans-serif"
|
|
274
|
+
}}
|
|
275
|
+
>
|
|
276
|
+
<h1>
|
|
277
|
+
🍔 Router + Styling + Assets Demo
|
|
278
|
+
</h1>
|
|
279
|
+
<p>
|
|
280
|
+
This home page combines
|
|
281
|
+
{" "}
|
|
282
|
+
<strong>
|
|
283
|
+
React Router,
|
|
284
|
+
</strong>
|
|
285
|
+
{" "}
|
|
286
|
+
<strong>
|
|
287
|
+
pure CSS styling,
|
|
288
|
+
</strong>
|
|
289
|
+
{" "}
|
|
290
|
+
<strong>
|
|
291
|
+
static assets
|
|
292
|
+
</strong>
|
|
293
|
+
{" "}
|
|
294
|
+
and
|
|
295
|
+
{" "}
|
|
296
|
+
<strong>
|
|
297
|
+
nested folder imports
|
|
298
|
+
</strong>
|
|
299
|
+
</p>
|
|
300
|
+
<div className="container">
|
|
301
|
+
<h2
|
|
302
|
+
style={{
|
|
303
|
+
"color": "white",
|
|
304
|
+
"textShadow": "2px 2px 4px rgba(0,0,0,0.6)"
|
|
305
|
+
}}
|
|
306
|
+
>
|
|
307
|
+
CSS Background Image
|
|
308
|
+
</h2>
|
|
309
|
+
<p
|
|
310
|
+
style={{
|
|
311
|
+
"color": "white",
|
|
312
|
+
"maxWidth": "480px",
|
|
313
|
+
"textShadow": "1px 1px 3px rgba(0,0,0,0.7)"
|
|
314
|
+
}}
|
|
315
|
+
>
|
|
316
|
+
This section uses the burger image as a background via CSS, just like the
|
|
317
|
+
{" "}
|
|
318
|
+
<code>
|
|
319
|
+
asset-serving/css-with-image
|
|
320
|
+
</code>
|
|
321
|
+
{" "}
|
|
322
|
+
example.
|
|
323
|
+
</p>
|
|
324
|
+
</div>
|
|
325
|
+
<Card
|
|
326
|
+
title="TypeScript Card Component"
|
|
327
|
+
description="This card is built with TypeScript and demonstrates type-safe component usage in Jac"
|
|
328
|
+
variant="highlighted"
|
|
329
|
+
>
|
|
330
|
+
<p
|
|
331
|
+
style={{"margin": "0.5rem 0", "color": "#374151"}}
|
|
332
|
+
>
|
|
333
|
+
This is a TypeScript component imported and used in Jac code!
|
|
334
|
+
</p>
|
|
335
|
+
</Card>
|
|
336
|
+
<div className="card">
|
|
337
|
+
<h3>
|
|
338
|
+
Direct <img> asset
|
|
339
|
+
</h3>
|
|
340
|
+
<img
|
|
341
|
+
src="/static/assets/burger.png"
|
|
342
|
+
alt="Burger asset served by Jac"
|
|
343
|
+
className="burgerImage"
|
|
344
|
+
/>
|
|
345
|
+
<p
|
|
346
|
+
style={{"marginTop": "0.75rem", "color": "#555"}}
|
|
347
|
+
>
|
|
348
|
+
This image is served from the project
|
|
349
|
+
{" "}
|
|
350
|
+
<code>
|
|
351
|
+
assets/
|
|
352
|
+
</code>
|
|
353
|
+
{" "}
|
|
354
|
+
folder using the
|
|
355
|
+
{" "}
|
|
356
|
+
<code>
|
|
357
|
+
/static/assets/
|
|
358
|
+
</code>
|
|
359
|
+
{" "}
|
|
360
|
+
path.
|
|
361
|
+
</p>
|
|
362
|
+
</div>
|
|
363
|
+
<div
|
|
364
|
+
style={{"marginTop": "2rem"}}
|
|
365
|
+
>
|
|
366
|
+
<h3>
|
|
367
|
+
Counter with pure CSS classes
|
|
368
|
+
</h3>
|
|
369
|
+
<p>
|
|
370
|
+
You've clicked the burger
|
|
371
|
+
{" "}
|
|
372
|
+
<strong>
|
|
373
|
+
{count}
|
|
374
|
+
</strong>
|
|
375
|
+
{" "}
|
|
376
|
+
times.
|
|
377
|
+
</p>
|
|
378
|
+
<button
|
|
379
|
+
onClick={lambda e: any -> None{ count = count + 1;} }
|
|
380
|
+
style={{
|
|
381
|
+
"padding": "0.6rem 1.4rem",
|
|
382
|
+
"fontSize": "1rem",
|
|
383
|
+
"backgroundColor": "#ff6b35",
|
|
384
|
+
"color": "white",
|
|
385
|
+
"border": "none",
|
|
386
|
+
"borderRadius": "6px",
|
|
387
|
+
"cursor": "pointer",
|
|
388
|
+
"boxShadow": "0 2px 4px rgba(0,0,0,0.2)"
|
|
389
|
+
}}
|
|
390
|
+
>
|
|
391
|
+
Click the Burger! 🍔
|
|
392
|
+
</button>
|
|
393
|
+
</div>
|
|
394
|
+
<div
|
|
395
|
+
style={{"marginTop": "2rem"}}
|
|
396
|
+
>
|
|
397
|
+
<h3>
|
|
398
|
+
Backend Walkers
|
|
399
|
+
</h3>
|
|
400
|
+
<p>
|
|
401
|
+
Basic example walkers:
|
|
402
|
+
{" "}
|
|
403
|
+
<code>
|
|
404
|
+
ping_server
|
|
405
|
+
</code>
|
|
406
|
+
{" "}
|
|
407
|
+
and
|
|
408
|
+
{" "}
|
|
409
|
+
<code>
|
|
410
|
+
get_server_message
|
|
411
|
+
</code>
|
|
412
|
+
</p>
|
|
413
|
+
<button
|
|
414
|
+
onClick={lambda e: any -> None{ handlePing();} }
|
|
415
|
+
style={{
|
|
416
|
+
"padding": "0.5rem 1.2rem",
|
|
417
|
+
"marginRight": "0.75rem",
|
|
418
|
+
"backgroundColor": "#3b82f6",
|
|
419
|
+
"color": "white",
|
|
420
|
+
"border": "none",
|
|
421
|
+
"borderRadius": "6px",
|
|
422
|
+
"cursor": "pointer"
|
|
423
|
+
}}
|
|
424
|
+
>
|
|
425
|
+
Ping Backend
|
|
426
|
+
</button>
|
|
427
|
+
<button
|
|
428
|
+
onClick={lambda e: any -> None{ handleCreateSampleTodo();} }
|
|
429
|
+
style={{
|
|
430
|
+
"padding": "0.5rem 1.2rem",
|
|
431
|
+
"backgroundColor": "#10b981",
|
|
432
|
+
"color": "white",
|
|
433
|
+
"border": "none",
|
|
434
|
+
"borderRadius": "6px",
|
|
435
|
+
"cursor": "pointer"
|
|
436
|
+
}}
|
|
437
|
+
>
|
|
438
|
+
Create Sample Todo
|
|
439
|
+
</button>
|
|
440
|
+
{pingResult
|
|
441
|
+
and (
|
|
442
|
+
<span
|
|
443
|
+
style={{"marginLeft": "0.5rem", "color": "#374151"}}
|
|
444
|
+
>
|
|
445
|
+
Result:
|
|
446
|
+
{" "}
|
|
447
|
+
<code>
|
|
448
|
+
{pingResult}
|
|
449
|
+
</code>
|
|
450
|
+
</span>
|
|
451
|
+
)}
|
|
452
|
+
{serverMessage
|
|
453
|
+
and (
|
|
454
|
+
<p
|
|
455
|
+
style={{"marginTop": "0.75rem", "color": "#374151"}}
|
|
456
|
+
>
|
|
457
|
+
Message:
|
|
458
|
+
{" "}
|
|
459
|
+
<code>
|
|
460
|
+
{serverMessage}
|
|
461
|
+
</code>
|
|
462
|
+
</p>
|
|
463
|
+
)}
|
|
464
|
+
{lastTodoMessage
|
|
465
|
+
and (
|
|
466
|
+
<p
|
|
467
|
+
style={{"marginTop": "0.5rem", "color": "#111827"}}
|
|
468
|
+
>
|
|
469
|
+
{lastTodoMessage}
|
|
470
|
+
</p>
|
|
471
|
+
)}
|
|
472
|
+
</div>
|
|
473
|
+
<div
|
|
474
|
+
style={{"marginTop": "2rem"}}
|
|
475
|
+
>
|
|
476
|
+
<h3>
|
|
477
|
+
Web Worker
|
|
478
|
+
</h3>
|
|
479
|
+
<p>
|
|
480
|
+
This demonstrates how to communicate with a
|
|
481
|
+
{" "}
|
|
482
|
+
<strong>Python backend worker</strong>
|
|
483
|
+
{" "}
|
|
484
|
+
using Web Workers for asynchronous processing.
|
|
485
|
+
</p>
|
|
486
|
+
<p
|
|
487
|
+
style={{"fontSize": "0.9rem", "color": "#666", "marginTop": "0.5rem"}}
|
|
488
|
+
>
|
|
489
|
+
File:
|
|
490
|
+
{" "}
|
|
491
|
+
<code>
|
|
492
|
+
worker.py
|
|
493
|
+
</code>
|
|
494
|
+
{" "}
|
|
495
|
+
— Runs in a separate thread to avoid blocking the UI.
|
|
496
|
+
</p>
|
|
497
|
+
<button
|
|
498
|
+
onClick={lambda -> None { handleClick(); }}
|
|
499
|
+
style={{
|
|
500
|
+
"padding": "0.5rem 1.2rem",
|
|
501
|
+
"marginRight": "0.75rem",
|
|
502
|
+
"backgroundColor": "#d73bf6ff",
|
|
503
|
+
"color": "white",
|
|
504
|
+
"border": "none",
|
|
505
|
+
"borderRadius": "6px",
|
|
506
|
+
"cursor": "pointer"
|
|
507
|
+
}}
|
|
508
|
+
>
|
|
509
|
+
Call Python Worker
|
|
510
|
+
</button>
|
|
511
|
+
{message && (
|
|
512
|
+
<p style={{ marginTop: "1rem", fontWeight: "bold" }}>
|
|
513
|
+
{message}
|
|
514
|
+
</p>
|
|
515
|
+
)}
|
|
516
|
+
</div>
|
|
517
|
+
</div>;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
def:pub app -> any {
|
|
521
|
+
return <Router>
|
|
522
|
+
<div
|
|
523
|
+
style={{"fontFamily": "system-ui, -apple-system, sans-serif"}}
|
|
524
|
+
>
|
|
525
|
+
<Navigation />
|
|
526
|
+
<div
|
|
527
|
+
style={{
|
|
528
|
+
"maxWidth": "960px",
|
|
529
|
+
"margin": "0 auto",
|
|
530
|
+
"padding": "0 1rem 3rem 1rem"
|
|
531
|
+
}}
|
|
532
|
+
>
|
|
533
|
+
<Routes>
|
|
534
|
+
<Route
|
|
535
|
+
path="/"
|
|
536
|
+
element={<HomePage />}
|
|
537
|
+
/>
|
|
538
|
+
<Route
|
|
539
|
+
path="/login"
|
|
540
|
+
element={<LoginPage />}
|
|
541
|
+
/>
|
|
542
|
+
<Route
|
|
543
|
+
path="/signup"
|
|
544
|
+
element={<SignupPage />}
|
|
545
|
+
/>
|
|
546
|
+
<Route
|
|
547
|
+
path="/nested"
|
|
548
|
+
element={<NestedImportsDemo />}
|
|
549
|
+
/>
|
|
550
|
+
<Route
|
|
551
|
+
path="/features-test"
|
|
552
|
+
element={<FeaturesTest />}
|
|
553
|
+
/>
|
|
554
|
+
<Route
|
|
555
|
+
path="/landing"
|
|
556
|
+
element={<LandingPage />}
|
|
557
|
+
/>
|
|
558
|
+
<Route
|
|
559
|
+
path="/budget-planner"
|
|
560
|
+
element={<BudgetProvider>
|
|
561
|
+
<BudgetPlanner />
|
|
562
|
+
</BudgetProvider>}
|
|
563
|
+
/>
|
|
564
|
+
<Route
|
|
565
|
+
path="*"
|
|
566
|
+
element={<NotFound />}
|
|
567
|
+
/>
|
|
568
|
+
</Routes>
|
|
569
|
+
</div>
|
|
570
|
+
</div>
|
|
571
|
+
</Router>;
|
|
572
|
+
}
|
|
573
|
+
}
|