jac-client 0.2.2__py3-none-any.whl → 0.2.6__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 (202) hide show
  1. jac_client/examples/all-in-one/assets/workers/worker.py +5 -0
  2. jac_client/examples/all-in-one/src/app.jac +841 -0
  3. jac_client/examples/all-in-one/{button.jac → src/button.jac} +1 -1
  4. jac_client/examples/all-in-one/{components → src/components}/button.jac +1 -1
  5. jac_client/examples/asset-serving/css-with-image/{app.jac → src/app.jac} +2 -2
  6. jac_client/examples/asset-serving/image-asset/{app.jac → src/app.jac} +2 -2
  7. jac_client/examples/asset-serving/import-alias/{app.jac → src/app.jac} +7 -7
  8. jac_client/examples/basic/{app.jac → src/app.jac} +2 -2
  9. jac_client/examples/basic-auth/src/app.jac +377 -0
  10. jac_client/examples/basic-auth-with-router/{app.jac → src/app.jac} +18 -18
  11. jac_client/examples/basic-full-stack/{app.jac → src/app.jac} +175 -130
  12. jac_client/examples/css-styling/js-styling/{app.jac → src/app.jac} +6 -6
  13. jac_client/examples/css-styling/material-ui/{app.jac → src/app.jac} +5 -5
  14. jac_client/examples/css-styling/pure-css/{app.jac → src/app.jac} +6 -6
  15. jac_client/examples/css-styling/sass-example/{app.jac → src/app.jac} +6 -6
  16. jac_client/examples/css-styling/styled-components/{app.jac → src/app.jac} +5 -5
  17. jac_client/examples/css-styling/tailwind-example/{app.jac → src/app.jac} +6 -6
  18. jac_client/examples/full-stack-with-auth/{app.jac → src/app.jac} +37 -37
  19. jac_client/examples/little-x/{app.jac → src/app.jac} +27 -32
  20. jac_client/examples/little-x/src/submit-button.jac +16 -0
  21. jac_client/examples/nested-folders/nested-advance/{ButtonRoot.jac → src/ButtonRoot.jac} +1 -1
  22. jac_client/examples/nested-folders/nested-advance/{app.jac → src/app.jac} +1 -1
  23. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/ButtonSecondL.jac +1 -1
  24. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/Card.jac +1 -1
  25. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/level2/ButtonThirdL.jac +1 -1
  26. jac_client/examples/nested-folders/nested-basic/{app.jac → src/app.jac} +2 -2
  27. jac_client/examples/nested-folders/nested-basic/{button.jac → src/button.jac} +1 -1
  28. jac_client/examples/nested-folders/nested-basic/{components → src/components}/button.jac +1 -1
  29. jac_client/examples/ts-support/src/app.jac +35 -0
  30. jac_client/examples/with-router/{app.jac → src/app.jac} +11 -11
  31. jac_client/plugin/cli.jac +547 -0
  32. jac_client/plugin/client.jac +52 -0
  33. jac_client/plugin/client_runtime.cl.jac +38 -0
  34. jac_client/plugin/impl/client.impl.jac +134 -0
  35. jac_client/plugin/impl/client_runtime.impl.jac +177 -0
  36. jac_client/plugin/impl/vite_client_bundle.impl.jac +72 -0
  37. jac_client/plugin/plugin_config.jac +195 -0
  38. jac_client/plugin/src/__init__.jac +20 -0
  39. jac_client/plugin/src/asset_processor.jac +33 -0
  40. jac_client/plugin/src/babel_processor.jac +18 -0
  41. jac_client/plugin/src/compiler.jac +66 -0
  42. jac_client/plugin/src/config_loader.jac +32 -0
  43. jac_client/plugin/src/impl/asset_processor.impl.jac +127 -0
  44. jac_client/plugin/src/impl/babel_processor.impl.jac +84 -0
  45. jac_client/plugin/src/impl/compiler.impl.jac +251 -0
  46. jac_client/plugin/src/impl/config_loader.impl.jac +119 -0
  47. jac_client/plugin/src/impl/import_processor.impl.jac +33 -0
  48. jac_client/plugin/src/impl/jac_to_js.impl.jac +41 -0
  49. jac_client/plugin/src/impl/package_installer.impl.jac +105 -0
  50. jac_client/plugin/src/impl/vite_bundler.impl.jac +513 -0
  51. jac_client/plugin/src/import_processor.jac +19 -0
  52. jac_client/plugin/src/jac_to_js.jac +35 -0
  53. jac_client/plugin/src/package_installer.jac +26 -0
  54. jac_client/plugin/src/vite_bundler.jac +36 -0
  55. jac_client/plugin/vite_client_bundle.jac +31 -0
  56. jac_client/tests/conftest.py +281 -0
  57. jac_client/tests/fixtures/basic-app/app.jac +2 -2
  58. jac_client/tests/fixtures/cl_file/app.cl.jac +2 -2
  59. jac_client/tests/fixtures/client_app_with_antd/app.jac +1 -1
  60. jac_client/tests/fixtures/js_import/app.jac +5 -5
  61. jac_client/tests/fixtures/spawn_test/app.jac +7 -7
  62. jac_client/tests/fixtures/with-ts/app.jac +35 -0
  63. jac_client/tests/test_cli.py +755 -0
  64. jac_client/tests/test_it.py +347 -67
  65. {jac_client-0.2.2.dist-info → jac_client-0.2.6.dist-info}/METADATA +30 -24
  66. jac_client-0.2.6.dist-info/RECORD +74 -0
  67. {jac_client-0.2.2.dist-info → jac_client-0.2.6.dist-info}/WHEEL +2 -1
  68. jac_client-0.2.6.dist-info/entry_points.txt +4 -0
  69. jac_client-0.2.6.dist-info/top_level.txt +1 -0
  70. jac_client/docs/README.md +0 -689
  71. jac_client/docs/advanced-state.md +0 -1265
  72. jac_client/docs/asset-serving/intro.md +0 -209
  73. jac_client/docs/assets/pipe_line-v2.svg +0 -32
  74. jac_client/docs/assets/pipe_line.png +0 -0
  75. jac_client/docs/file-system/app.jac.md +0 -121
  76. jac_client/docs/file-system/backend-frontend.md +0 -217
  77. jac_client/docs/file-system/intro.md +0 -72
  78. jac_client/docs/file-system/nested-imports.md +0 -348
  79. jac_client/docs/guide-example/intro.md +0 -115
  80. jac_client/docs/guide-example/step-01-setup.md +0 -270
  81. jac_client/docs/guide-example/step-02-components.md +0 -416
  82. jac_client/docs/guide-example/step-03-styling.md +0 -478
  83. jac_client/docs/guide-example/step-04-todo-ui.md +0 -477
  84. jac_client/docs/guide-example/step-05-local-state.md +0 -530
  85. jac_client/docs/guide-example/step-06-events.md +0 -749
  86. jac_client/docs/guide-example/step-07-effects.md +0 -468
  87. jac_client/docs/guide-example/step-08-walkers.md +0 -534
  88. jac_client/docs/guide-example/step-09-authentication.md +0 -586
  89. jac_client/docs/guide-example/step-10-routing.md +0 -539
  90. jac_client/docs/guide-example/step-11-final.md +0 -963
  91. jac_client/docs/imports.md +0 -1141
  92. jac_client/docs/lifecycle-hooks.md +0 -773
  93. jac_client/docs/routing.md +0 -659
  94. jac_client/docs/styling/intro.md +0 -249
  95. jac_client/docs/styling/js-styling.md +0 -367
  96. jac_client/docs/styling/material-ui.md +0 -341
  97. jac_client/docs/styling/pure-css.md +0 -299
  98. jac_client/docs/styling/sass.md +0 -403
  99. jac_client/docs/styling/styled-components.md +0 -395
  100. jac_client/docs/styling/tailwind.md +0 -298
  101. jac_client/examples/all-in-one/.babelrc +0 -9
  102. jac_client/examples/all-in-one/README.md +0 -16
  103. jac_client/examples/all-in-one/app.jac +0 -426
  104. jac_client/examples/all-in-one/assets/burger.png +0 -0
  105. jac_client/examples/all-in-one/package.json +0 -29
  106. jac_client/examples/all-in-one/styles.css +0 -26
  107. jac_client/examples/all-in-one/vite.config.js +0 -28
  108. jac_client/examples/asset-serving/css-with-image/.babelrc +0 -9
  109. jac_client/examples/asset-serving/css-with-image/README.md +0 -91
  110. jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
  111. jac_client/examples/asset-serving/css-with-image/package.json +0 -28
  112. jac_client/examples/asset-serving/css-with-image/styles.css +0 -26
  113. jac_client/examples/asset-serving/css-with-image/vite.config.js +0 -28
  114. jac_client/examples/asset-serving/image-asset/.babelrc +0 -9
  115. jac_client/examples/asset-serving/image-asset/README.md +0 -119
  116. jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
  117. jac_client/examples/asset-serving/image-asset/package.json +0 -28
  118. jac_client/examples/asset-serving/image-asset/styles.css +0 -26
  119. jac_client/examples/asset-serving/image-asset/vite.config.js +0 -28
  120. jac_client/examples/asset-serving/import-alias/.babelrc +0 -9
  121. jac_client/examples/asset-serving/import-alias/README.md +0 -83
  122. jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
  123. jac_client/examples/asset-serving/import-alias/package.json +0 -28
  124. jac_client/examples/asset-serving/import-alias/vite.config.js +0 -28
  125. jac_client/examples/basic/.babelrc +0 -9
  126. jac_client/examples/basic/README.md +0 -16
  127. jac_client/examples/basic/package.json +0 -27
  128. jac_client/examples/basic/vite.config.js +0 -27
  129. jac_client/examples/basic-auth/.babelrc +0 -9
  130. jac_client/examples/basic-auth/README.md +0 -16
  131. jac_client/examples/basic-auth/app.jac +0 -308
  132. jac_client/examples/basic-auth/package.json +0 -27
  133. jac_client/examples/basic-auth/vite.config.js +0 -27
  134. jac_client/examples/basic-auth-with-router/.babelrc +0 -9
  135. jac_client/examples/basic-auth-with-router/README.md +0 -60
  136. jac_client/examples/basic-auth-with-router/package.json +0 -28
  137. jac_client/examples/basic-auth-with-router/vite.config.js +0 -27
  138. jac_client/examples/basic-full-stack/.babelrc +0 -9
  139. jac_client/examples/basic-full-stack/README.md +0 -18
  140. jac_client/examples/basic-full-stack/package.json +0 -28
  141. jac_client/examples/basic-full-stack/vite.config.js +0 -27
  142. jac_client/examples/css-styling/js-styling/.babelrc +0 -9
  143. jac_client/examples/css-styling/js-styling/README.md +0 -183
  144. jac_client/examples/css-styling/js-styling/package.json +0 -28
  145. jac_client/examples/css-styling/js-styling/styles.js +0 -100
  146. jac_client/examples/css-styling/js-styling/vite.config.js +0 -27
  147. jac_client/examples/css-styling/material-ui/.babelrc +0 -9
  148. jac_client/examples/css-styling/material-ui/README.md +0 -16
  149. jac_client/examples/css-styling/material-ui/package.json +0 -32
  150. jac_client/examples/css-styling/material-ui/vite.config.js +0 -27
  151. jac_client/examples/css-styling/pure-css/.babelrc +0 -9
  152. jac_client/examples/css-styling/pure-css/README.md +0 -16
  153. jac_client/examples/css-styling/pure-css/package.json +0 -28
  154. jac_client/examples/css-styling/pure-css/styles.css +0 -111
  155. jac_client/examples/css-styling/pure-css/vite.config.js +0 -27
  156. jac_client/examples/css-styling/sass-example/.babelrc +0 -9
  157. jac_client/examples/css-styling/sass-example/README.md +0 -16
  158. jac_client/examples/css-styling/sass-example/package.json +0 -29
  159. jac_client/examples/css-styling/sass-example/styles.scss +0 -153
  160. jac_client/examples/css-styling/sass-example/vite.config.js +0 -27
  161. jac_client/examples/css-styling/styled-components/.babelrc +0 -9
  162. jac_client/examples/css-styling/styled-components/README.md +0 -16
  163. jac_client/examples/css-styling/styled-components/package.json +0 -29
  164. jac_client/examples/css-styling/styled-components/styled.js +0 -90
  165. jac_client/examples/css-styling/styled-components/vite.config.js +0 -27
  166. jac_client/examples/css-styling/tailwind-example/.babelrc +0 -9
  167. jac_client/examples/css-styling/tailwind-example/README.md +0 -16
  168. jac_client/examples/css-styling/tailwind-example/global.css +0 -1
  169. jac_client/examples/css-styling/tailwind-example/package.json +0 -30
  170. jac_client/examples/css-styling/tailwind-example/vite.config.js +0 -29
  171. jac_client/examples/full-stack-with-auth/.babelrc +0 -9
  172. jac_client/examples/full-stack-with-auth/README.md +0 -16
  173. jac_client/examples/full-stack-with-auth/package.json +0 -28
  174. jac_client/examples/full-stack-with-auth/vite.config.js +0 -29
  175. jac_client/examples/little-x/package.json +0 -23
  176. jac_client/examples/little-x/submit-button.jac +0 -8
  177. jac_client/examples/nested-folders/nested-advance/.babelrc +0 -9
  178. jac_client/examples/nested-folders/nested-advance/README.md +0 -77
  179. jac_client/examples/nested-folders/nested-advance/package.json +0 -29
  180. jac_client/examples/nested-folders/nested-advance/vite.config.js +0 -28
  181. jac_client/examples/nested-folders/nested-basic/.babelrc +0 -9
  182. jac_client/examples/nested-folders/nested-basic/README.md +0 -183
  183. jac_client/examples/nested-folders/nested-basic/app.js +0 -7
  184. jac_client/examples/nested-folders/nested-basic/package.json +0 -28
  185. jac_client/examples/nested-folders/nested-basic/vite.config.js +0 -27
  186. jac_client/examples/with-router/.babelrc +0 -9
  187. jac_client/examples/with-router/README.md +0 -17
  188. jac_client/examples/with-router/package.json +0 -28
  189. jac_client/examples/with-router/vite.config.js +0 -27
  190. jac_client/plugin/cli.py +0 -244
  191. jac_client/plugin/client.py +0 -152
  192. jac_client/plugin/client_runtime.jac +0 -234
  193. jac_client/plugin/vite_client_bundle.py +0 -503
  194. jac_client/tests/fixtures/js_import/utils.js +0 -21
  195. jac_client/tests/fixtures/package-lock.json +0 -329
  196. jac_client/tests/fixtures/package.json +0 -11
  197. jac_client/tests/test_asset_examples.py +0 -322
  198. jac_client/tests/test_cl.py +0 -530
  199. jac_client/tests/test_create_jac_app.py +0 -131
  200. jac_client/tests/test_nested_file.py +0 -374
  201. jac_client-0.2.2.dist-info/RECORD +0 -171
  202. jac_client-0.2.2.dist-info/entry_points.txt +0 -4
@@ -0,0 +1,134 @@
1
+ import from jaclang.project.config { get_config }
2
+
3
+ """Send static file response (images, fonts, etc.)."""
4
+ impl JacClient.send_static_file(
5
+ handler: BaseHTTPRequestHandler, file_path: Path, content_type: (str | None) = None
6
+ ) -> None {
7
+ import from jaclang.runtimelib.server { ResponseBuilder }
8
+ if (not file_path.exists() or not file_path.is_file()) {
9
+ ResponseBuilder.send_json(handler, 404, {'error': 'File not found'});
10
+ return;
11
+ }
12
+ try {
13
+ file_content = file_path.read_bytes();
14
+ if (content_type is None) {
15
+ (content_type, _) = mimetypes.guess_type(str(file_path));
16
+ if (content_type is None) {
17
+ content_type = 'application/octet-stream';
18
+ }
19
+ }
20
+ handler.send_response(200);
21
+ handler.send_header('Content-Type', content_type);
22
+ handler.send_header('Content-Length', str(len(file_content)));
23
+ handler.send_header('Cache-Control', 'public, max-age=3600');
24
+ ResponseBuilder._add_cors_headers(handler);
25
+ ResponseBuilder._add_custom_headers(handler);
26
+ handler.end_headers();
27
+ handler.wfile.write(file_content);
28
+ } except Exception as exc {
29
+ ResponseBuilder.send_json(handler, 500, {'error': str(exc)});
30
+ }
31
+ }
32
+
33
+ """Get a module introspector for the supplied module."""
34
+ impl JacClient.get_module_introspector(
35
+ module_name: str, base_path: (str | None)
36
+ ) -> ModuleIntrospector {
37
+ return JacClientModuleIntrospector(module_name, base_path);
38
+ }
39
+
40
+ """Build a client bundle for the supplied module."""
41
+ impl JacClient.build_client_bundle(
42
+ module: types.ModuleType, force: bool = False
43
+ ) -> ClientBundle {
44
+ builder = JacClient.get_client_bundle_builder();
45
+ return builder.build(module, force=force);
46
+ }
47
+
48
+ """Get the client bundle builder instance."""
49
+ impl JacClient.get_client_bundle_builder -> ViteClientBundleBuilder {
50
+ import from jaclang.project.config { find_project_root }
51
+ # Find project root by looking for jac.toml (base_path_dir might be src/ for entry files)
52
+ base_path_dir = Path(Jac.base_path_dir);
53
+ project_root_result = find_project_root(base_path_dir);
54
+ if project_root_result {
55
+ (base_path, _) = project_root_result;
56
+ } else {
57
+ # Fallback to base_path_dir if no project root found
58
+ base_path = base_path_dir;
59
+ }
60
+ # package.json should only exist in .client-build/.jac-client.configs/
61
+ generated_package_json = base_path / '.client-build' / '.jac-client.configs' / 'package.json';
62
+ # Generate package.json if it doesn't exist
63
+ if not generated_package_json.exists() {
64
+ # Use ViteBundler to generate package.json from config.json
65
+ bundler = ViteBundler(base_path);
66
+ generated_path = bundler.create_package_json();
67
+ # Verify the file was created and resolve to absolute path
68
+ if not generated_path.exists() {
69
+ raise ClientBundleError(
70
+ f'Failed to generate package.json at {generated_path}'
71
+ ) ;
72
+ }
73
+ package_json_path = generated_path.resolve();
74
+ } else {
75
+ package_json_path = generated_package_json.resolve();
76
+ }
77
+ # Final verification that package.json exists before creating builder
78
+ if not package_json_path.exists() {
79
+ raise ClientBundleError(
80
+ f'package.json not found at {package_json_path}. Expected at {generated_package_json}'
81
+ ) ;
82
+ }
83
+ output_dir = base_path / '.client-build' / 'dist';
84
+ runtime_path = Path(__file__).with_name('client_runtime.cl.jac');
85
+ return ViteClientBundleBuilder(
86
+ runtime_path=runtime_path,
87
+ vite_package_json=package_json_path,
88
+ vite_output_dir=output_dir,
89
+ vite_minify=False
90
+ );
91
+ }
92
+
93
+ """Render HTML page for client function using the Vite bundle."""
94
+ impl JacClientModuleIntrospector.render_page(
95
+ self: JacClientModuleIntrospector,
96
+ function_name: str,
97
+ args: dict[(str, Any)],
98
+ username: str
99
+ ) -> dict[str, Any] {
100
+ self.load();
101
+ available_exports = (
102
+ set(self._client_manifest.get('exports', []))
103
+ or set(self.get_client_functions().keys())
104
+ );
105
+ if (function_name not in available_exports) {
106
+ raise ValueError(f"Client function '{function_name}' not found") ;
107
+ }
108
+ bundle_hash = self.ensure_bundle();
109
+ import from jaclang.project.config { find_project_root }
110
+ # Find project root by looking for jac.toml (base_path_dir might be src/ for entry files)
111
+ base_path_dir = Path(Jac.base_path_dir);
112
+ project_root_result = find_project_root(base_path_dir);
113
+ if project_root_result {
114
+ (base_path, _) = project_root_result;
115
+ } else {
116
+ # Fallback to base_path_dir if no project root found
117
+ base_path = base_path_dir;
118
+ }
119
+ dist_dir = base_path / '.client-build' / 'dist';
120
+ css_link = '';
121
+ css_file = dist_dir / 'main.css';
122
+ if css_file.exists() {
123
+ css_hash = hashlib.sha256(css_file.read_bytes()).hexdigest()[:8];
124
+ css_link = f'<link rel="stylesheet" href="/static/main.css?hash={css_hash}"/>';
125
+ }
126
+ head_content = f'<meta charset="utf-8"/>\n <title>{html.escape(
127
+ function_name
128
+ )}</title>';
129
+ if css_link {
130
+ head_content += f"\n {css_link}";
131
+ }
132
+ page = f'<!DOCTYPE html><html lang="en"><head>{head_content}</head><body><div id="root"></div><script src="/static/client.js?hash={bundle_hash}" defer></script></body></html>';
133
+ return {'html': page, 'bundle_hash': bundle_hash, 'bundle_code': self._bundle.code};
134
+ }
@@ -0,0 +1,177 @@
1
+ impl __jacJsx(tag: any, props: dict = {}, children: any = []) -> any {
2
+ if tag == None {
3
+ tag = React.Fragment;
4
+ }
5
+ childrenArray = [];
6
+ if children != None {
7
+ if Array.isArray(children) {
8
+ childrenArray = children;
9
+ } else {
10
+ childrenArray = [children];
11
+ }
12
+ }
13
+ reactChildren = [];
14
+ for child in childrenArray {
15
+ if child != None {
16
+ reactChildren.push(child);
17
+ }
18
+ }
19
+ if reactChildren.length > 0 {
20
+ args = [tag, props];
21
+ for child in reactChildren {
22
+ args.push(child);
23
+ }
24
+ return React.createElement.apply(React, args);
25
+ } else {
26
+ return React.createElement(tag, props);
27
+ }
28
+ }
29
+
30
+ impl useRouter -> dict {
31
+ navigate = reactRouterUseNavigate();
32
+ location = reactRouterUseLocation();
33
+ params = reactRouterUseParams();
34
+ return {
35
+ "navigate": navigate,
36
+ "location": location,
37
+ "params": params,
38
+ "pathname": location.pathname,
39
+ "search": location.search,
40
+ "hash": location.hash
41
+ };
42
+ }
43
+
44
+ impl navigate(path: str) -> None {
45
+ window.location.hash = "#" + path;
46
+ }
47
+
48
+ impl __jacSpawn(left: str, right: str = "", fields: dict = {}) -> any {
49
+ token = __getLocalStorage("jac_token");
50
+ url = f"/walker/{left}";
51
+ if right != "" {
52
+ url = f"/walker/{left}/{right}";
53
+ }
54
+ response = await fetch(
55
+ url,
56
+ {
57
+ "method": "POST",
58
+ "accept": "application/json",
59
+ "headers": {
60
+ "Content-Type": "application/json",
61
+ "Authorization": f"Bearer {token}" if token else ""
62
+ },
63
+ "body": JSON.stringify(fields)
64
+ }
65
+ );
66
+ if not response.ok {
67
+ error_text = await response.json();
68
+ raise Exception(f"Walker {walker} failed: {error_text}") ;
69
+ }
70
+ return await response.json();
71
+ }
72
+
73
+ impl jacSpawn(left: str, right: str = "", fields: dict = {}) -> any {
74
+ return __jacSpawn(left, right, fields);
75
+ }
76
+
77
+ impl __jacCallFunction(function_name: str, args: dict = {}) -> any {
78
+ token = __getLocalStorage("jac_token");
79
+ response = await fetch(
80
+ f"/function/{function_name}",
81
+ {
82
+ "method": "POST",
83
+ "headers": {
84
+ "Content-Type": "application/json",
85
+ "Authorization": f"Bearer {token}" if token else ""
86
+ },
87
+ "body": JSON.stringify({"args": args})
88
+ }
89
+ );
90
+ if not response.ok {
91
+ error_text = await response.text();
92
+ raise Exception(f"Function {function_name} failed: {error_text}") ;
93
+ }
94
+ data = JSON.parse(await response.text());
95
+ return data["result"];
96
+ }
97
+
98
+ impl jacSignup(username: str, password: str) -> dict {
99
+ response = await fetch(
100
+ "/user/register",
101
+ {
102
+ "method": "POST",
103
+ "headers": {"Content-Type": "application/json"},
104
+ "body": JSON.stringify({"username": username, "password": password})
105
+ }
106
+ );
107
+ if response.ok {
108
+ data = JSON.parse(await response.text());
109
+ token = data["token"];
110
+ if token {
111
+ __setLocalStorage("jac_token", token);
112
+ return {"success": True, "token": token, "username": username};
113
+ }
114
+ return {"success": False, "error": "No token received"};
115
+ } else {
116
+ error_text = await response.text();
117
+ try {
118
+ error_data = JSON.parse(error_text);
119
+ return {
120
+ "success": False,
121
+ "error": error_data["error"]
122
+ if error_data["error"] != None
123
+ else "Signup failed"
124
+ };
125
+ } except Exception {
126
+ return {"success": False, "error": error_text};
127
+ }
128
+ }
129
+ }
130
+
131
+ impl jacLogin(username: str, password: str) -> bool {
132
+ response = await fetch(
133
+ "/user/login",
134
+ {
135
+ "method": "POST",
136
+ "headers": {"Content-Type": "application/json"},
137
+ "body": JSON.stringify({"username": username, "password": password})
138
+ }
139
+ );
140
+ if response.ok {
141
+ data = JSON.parse(await response.text());
142
+ token = data["token"];
143
+ if token {
144
+ __setLocalStorage("jac_token", token);
145
+ return True;
146
+ }
147
+ }
148
+ return False;
149
+ }
150
+
151
+ impl jacLogout -> None {
152
+ __removeLocalStorage("jac_token");
153
+ }
154
+
155
+ impl jacIsLoggedIn -> bool {
156
+ token = __getLocalStorage("jac_token");
157
+ return token != None and token != "";
158
+ }
159
+
160
+ impl __getLocalStorage(key: str) -> str {
161
+ storage = globalThis.localStorage;
162
+ return storage.getItem(key) if storage else "";
163
+ }
164
+
165
+ impl __setLocalStorage(key: str, value: str) -> None {
166
+ storage = globalThis.localStorage;
167
+ if storage {
168
+ storage.setItem(key, value);
169
+ }
170
+ }
171
+
172
+ impl __removeLocalStorage(key: str) -> None {
173
+ storage = globalThis.localStorage;
174
+ if storage {
175
+ storage.removeItem(key);
176
+ }
177
+ }
@@ -0,0 +1,72 @@
1
+ """Clean up the compiled directory and its contents."""
2
+
3
+ impl ViteClientBundleBuilder.cleanup_temp_dir(self: ViteClientBundleBuilder) -> None {
4
+ if (not self.vite_package_json or not self.vite_package_json.exists()) {
5
+ return;
6
+ }
7
+ project_dir = self.vite_package_json.parent;
8
+ temp_dir = project_dir / 'compiled';
9
+ if temp_dir.exists() {
10
+ with contextlib.suppress(OSError, shutil.Error) {
11
+ shutil.rmtree(temp_dir);
12
+ }
13
+ }
14
+ }
15
+
16
+ """Override to use Vite bundling instead of simple concatenation."""
17
+ impl ViteClientBundleBuilder._compile_bundle(
18
+ self: ViteClientBundleBuilder, module: ModuleType, module_path: Path
19
+ ) -> ClientBundle {
20
+ compiler = self._get_compiler();
21
+ (bundle_code, bundle_hash, client_exports, client_globals) = compiler.compile_and_bundle(
22
+ module, module_path
23
+ );
24
+ return ClientBundle(
25
+ module_name=module.__name__,
26
+ code=bundle_code,
27
+ client_functions=client_exports,
28
+ client_globals=client_globals,
29
+ hash=bundle_hash
30
+ );
31
+ }
32
+
33
+ """Get or create the Vite compiler instance."""
34
+ impl ViteClientBundleBuilder._get_compiler(
35
+ self: ViteClientBundleBuilder
36
+ ) -> ViteCompiler {
37
+ if (self._compiler is None) {
38
+ if (not self.vite_package_json or not self.vite_package_json.exists()) {
39
+ raise ClientBundleError(
40
+ 'Vite package.json not found. Set vite_package_json when using ViteClientBundleBuilder'
41
+ ) ;
42
+ }
43
+ compile_to_js_func: Callable[([Path], tuple[(str, (ModuleType | None))])] = cast(
44
+ Callable[([Path], tuple[(str, (ModuleType | None))])], self._compile_to_js
45
+ );
46
+ self._compiler = ViteCompiler(
47
+ vite_package_json=self.vite_package_json,
48
+ vite_output_dir=self.vite_output_dir,
49
+ vite_minify=self.vite_minify,
50
+ runtime_path=self.runtime_path,
51
+ compile_to_js_func=compile_to_js_func,
52
+ extract_exports_func=self._extract_client_exports,
53
+ extract_globals_func=self._extract_client_globals
54
+ );
55
+ }
56
+ return self._compiler;
57
+ }
58
+
59
+ """Initialize the Vite-enhanced bundle builder."""
60
+ impl ViteClientBundleBuilder.init(
61
+ self: ViteClientBundleBuilder,
62
+ runtime_path: (Path | None) = None,
63
+ vite_output_dir: (Path | None) = None,
64
+ vite_package_json: (Path | None) = None,
65
+ vite_minify: bool = False
66
+ ) -> None {
67
+ super.init(runtime_path);
68
+ self.vite_output_dir = vite_output_dir;
69
+ self.vite_package_json = vite_package_json;
70
+ self.vite_minify = vite_minify;
71
+ self._compiler: (ViteCompiler | None) = None;
72
+ }
@@ -0,0 +1,195 @@
1
+ """Plugin configuration hooks for jac-client.
2
+
3
+ This module implements JacPluginConfig hooks to integrate with core's
4
+ configuration system, registering:
5
+ - Plugin metadata (name, version)
6
+ - Config schema for [plugins.client] section
7
+ - npm dependency type for [dependencies.npm] section
8
+ """
9
+
10
+ import subprocess;
11
+ import sys;
12
+ import from pathlib { Path }
13
+ import from typing { Any }
14
+ import from jaclang.pycore.runtime { hookimpl }
15
+ import from jaclang.project.config { JacConfig }
16
+
17
+ """Plugin configuration hooks for jac-client."""
18
+ class JacClientPluginConfig {
19
+ """Return plugin metadata."""
20
+ @hookimpl
21
+ static def get_plugin_metadata -> dict[str, Any] {
22
+ return {
23
+ "name": "client",
24
+ "version": "1.0.0",
25
+ "description": "Jac client-side rendering with Vite bundling"
26
+ };
27
+ }
28
+
29
+ """Return the plugin's configuration schema for [plugins.client]."""
30
+ @hookimpl
31
+ static def get_config_schema -> dict[str, Any] {
32
+ return {
33
+ "section": "client",
34
+ "options": {
35
+ "vite": {
36
+ "type": "dict",
37
+ "default": {},
38
+ "description": "Vite bundler configuration",
39
+ "nested": {
40
+ "plugins": {
41
+ "type": "list",
42
+ "default": [],
43
+ "description": "Vite plugins to include"
44
+ },
45
+ "lib_imports": {
46
+ "type": "list",
47
+ "default": [],
48
+ "description": "Library imports for vite.config.js"
49
+ },
50
+ "build": {
51
+ "type": "dict",
52
+ "default": {},
53
+ "description": "Vite build options"
54
+ },
55
+ "server": {
56
+ "type": "dict",
57
+ "default": {},
58
+ "description": "Vite dev server options"
59
+ },
60
+ "resolve": {
61
+ "type": "dict",
62
+ "default": {},
63
+ "description": "Vite resolve options"
64
+ }
65
+ }
66
+ },
67
+ "ts": {
68
+ "type": "dict",
69
+ "default": {},
70
+ "description": "TypeScript configuration overrides"
71
+ }
72
+ }
73
+ };
74
+ }
75
+
76
+ """Register npm as a dependency type for [dependencies.npm]."""
77
+ @hookimpl
78
+ static def register_dependency_type -> dict[str, Any] {
79
+ return {
80
+ "name": "npm",
81
+ "dev_name": "npm.dev",
82
+ "cli_flag": "--cl",
83
+ "install_dir": ".client-build/.jac-client.configs",
84
+ "install_handler": _npm_install_handler,
85
+ "install_all_handler": _npm_install_all_handler,
86
+ "remove_handler": _npm_remove_handler
87
+ };
88
+ }
89
+ }
90
+
91
+ """Install an npm package."""
92
+ def _npm_install_handler(
93
+ config: JacConfig,
94
+ package_name: str,
95
+ version: str | None = None,
96
+ is_dev: bool = False
97
+ ) -> None {
98
+ import from jac_client.plugin.src.vite_bundler { ViteBundler }
99
+
100
+ if config.project_root is None {
101
+ raise RuntimeError("No project root found") ;
102
+ }
103
+
104
+ project_dir = config.project_root;
105
+
106
+ # Add to config (core JacConfig handles this)
107
+ package_version = version or "latest";
108
+ config.add_dependency(package_name, package_version, dev=is_dev, dep_type="npm");
109
+ config.save();
110
+
111
+ # Generate package.json and run npm install
112
+ _regenerate_and_install(project_dir);
113
+ }
114
+
115
+ """Install all npm packages from jac.toml."""
116
+ def _npm_install_all_handler(config: JacConfig) -> None {
117
+ if config.project_root is None {
118
+ raise RuntimeError("No project root found") ;
119
+ }
120
+
121
+ _regenerate_and_install(config.project_root);
122
+ }
123
+
124
+ """Remove an npm package."""
125
+ def _npm_remove_handler(
126
+ config: JacConfig, package_name: str, is_dev: bool = False
127
+ ) -> None {
128
+ if config.project_root is None {
129
+ raise RuntimeError("No project root found") ;
130
+ }
131
+
132
+ project_dir = config.project_root;
133
+
134
+ # Remove from config (core JacConfig handles this)
135
+ result = config.remove_dependency(package_name, dev=is_dev, dep_type="npm");
136
+ if not result {
137
+ deps_key = "dev-dependencies" if is_dev else "dependencies";
138
+ raise RuntimeError(f'Package "{package_name}" not found in {deps_key}') ;
139
+ }
140
+
141
+ config.save();
142
+
143
+ # Regenerate package.json and run npm install
144
+ _regenerate_and_install(project_dir);
145
+ }
146
+
147
+ """Regenerate package.json from jac.toml and run npm install."""
148
+ def _regenerate_and_install(project_dir: Path) -> None {
149
+ import from jac_client.plugin.src.vite_bundler { ViteBundler }
150
+ import shutil;
151
+
152
+ bundler = ViteBundler(project_dir);
153
+ bundler.create_package_json();
154
+
155
+ # Install to .client-build/ directory where babel processor expects it
156
+ build_dir = project_dir / '.client-build';
157
+ build_dir.mkdir(exist_ok=True);
158
+
159
+ # Copy package.json to .client-build/ for npm install
160
+ configs_package_json = build_dir / '.jac-client.configs' / 'package.json';
161
+ build_package_json = build_dir / 'package.json';
162
+ if configs_package_json.exists() {
163
+ shutil.copy2(configs_package_json, build_package_json);
164
+ }
165
+
166
+ try {
167
+ subprocess.run(
168
+ ["npm", "install"],
169
+ cwd=build_dir,
170
+ check=True,
171
+ capture_output=True,
172
+ text=True
173
+ );
174
+ } except subprocess.CalledProcessError as e {
175
+ raise RuntimeError(f"Failed to install npm packages: {e.stderr}") from e ;
176
+ } except FileNotFoundError {
177
+ raise RuntimeError(
178
+ "npm command not found. Ensure Node.js and npm are installed."
179
+ ) from None ;
180
+ } finally {
181
+ # Clean up temporary package.json
182
+ if build_package_json.exists() {
183
+ build_package_json.unlink();
184
+ }
185
+ # Move package-lock.json to .jac-client.configs/ if it exists
186
+ build_package_lock = build_dir / 'package-lock.json';
187
+ if build_package_lock.exists() {
188
+ configs_package_lock = build_dir / '.jac-client.configs' / 'package-lock.json';
189
+ if configs_package_lock.exists() {
190
+ configs_package_lock.unlink();
191
+ }
192
+ build_package_lock.rename(configs_package_lock);
193
+ }
194
+ }
195
+ }
@@ -0,0 +1,20 @@
1
+ """Vite client bundle processing modules."""
2
+ import from jac_client.plugin.src.asset_processor { AssetProcessor }
3
+ import from jac_client.plugin.src.babel_processor { BabelProcessor }
4
+ import from jac_client.plugin.src.compiler { ViteCompiler }
5
+ import from jac_client.plugin.src.config_loader { JacClientConfig }
6
+ import from jac_client.plugin.src.import_processor { ImportProcessor }
7
+ import from jac_client.plugin.src.jac_to_js { JacToJSCompiler }
8
+ import from jac_client.plugin.src.package_installer { PackageInstaller }
9
+ import from jac_client.plugin.src.vite_bundler { ViteBundler }
10
+
11
+ glob __all__ = [
12
+ 'AssetProcessor',
13
+ 'BabelProcessor',
14
+ 'ViteCompiler',
15
+ 'JacClientConfig',
16
+ 'ImportProcessor',
17
+ 'JacToJSCompiler',
18
+ 'ViteBundler',
19
+ 'PackageInstaller'
20
+ ];
@@ -0,0 +1,33 @@
1
+ """Asset file processing and copying utilities."""
2
+ import contextlib;
3
+ import shutil;
4
+ import from pathlib { Path }
5
+ import from jaclang.project.config { get_config }
6
+
7
+ """Handles copying of asset files (CSS, images, fonts, etc.) between directories."""
8
+ class AssetProcessor {
9
+ with entry {
10
+ ASSET_EXTENSIONS = {'.css','.scss','.sass','.less','.svg','.png','.jpg','.jpeg','.gif','.webp','.ico','.woff','.woff2','.ttf','.eot','.otf','.mp4','.webm','.mp3','.wav'};
11
+ }
12
+
13
+ def copy_assets(
14
+ self: AssetProcessor,
15
+ src_dir: Path,
16
+ dest_dir: Path,
17
+ preserve_structure: bool = True
18
+ ) -> None;
19
+
20
+ def copy_typescript_files(
21
+ self: AssetProcessor,
22
+ src_dir: Path,
23
+ dest_dir: Path,
24
+ preserve_structure: bool = True
25
+ ) -> None;
26
+
27
+ def copy_custom_asset_types(
28
+ self: AssetProcessor,
29
+ src_dir: Path,
30
+ dest_dir: Path,
31
+ preserve_structure: bool = True
32
+ ) -> None;
33
+ }
@@ -0,0 +1,18 @@
1
+ """Babel processing for JavaScript transpilation."""
2
+ import subprocess;
3
+ import from pathlib { Path }
4
+ import from jaclang.runtimelib.client_bundle { ClientBundleError }
5
+ import from .asset_processor { AssetProcessor }
6
+ import from .vite_bundler { ViteBundler }
7
+
8
+ """Handles Babel compilation of JavaScript files."""
9
+ class BabelProcessor {
10
+ def init(self: BabelProcessor, project_dir: Path);
11
+ def compile(self: BabelProcessor) -> None;
12
+ def copy_assets_after_compile(
13
+ self: BabelProcessor,
14
+ compiled_dir: Path,
15
+ build_dir: Path,
16
+ asset_processor: AssetProcessor
17
+ ) -> None;
18
+ }