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,66 @@
1
+ """Main compilation orchestration module."""
2
+ import contextlib;
3
+ import from collections.abc { Callable }
4
+ import from pathlib { Path }
5
+ import from types { ModuleType }
6
+ import from typing { TYPE_CHECKING, Any }
7
+ import from jaclang.runtimelib.client_bundle { ClientBundleError }
8
+ import from .asset_processor { AssetProcessor }
9
+ import from .babel_processor { BabelProcessor }
10
+ import from .import_processor { ImportProcessor }
11
+ import from .jac_to_js { JacToJSCompiler }
12
+ import from .vite_bundler { ViteBundler }
13
+
14
+ with entry {
15
+ if TYPE_CHECKING { }
16
+ }
17
+
18
+ """Orchestrates the compilation process for Vite client bundles."""
19
+ class ViteCompiler {
20
+ with entry {
21
+ ROUTER_EXPORTS = [
22
+ 'Router',
23
+ 'Routes',
24
+ 'Route',
25
+ 'Link',
26
+ 'Navigate',
27
+ 'useNavigate',
28
+ 'useLocation',
29
+ 'useParams'
30
+ ];
31
+ }
32
+
33
+ def init(
34
+ self: ViteCompiler,
35
+ vite_package_json: Path,
36
+ vite_output_dir: (Path | None) = None,
37
+ vite_minify: bool = False,
38
+ runtime_path: (Path | None) = None,
39
+ compile_to_js_func:
40
+ (Callable[([Path], tuple[(str, (ModuleType | None))])] | None) = None,
41
+ extract_exports_func: (Callable[([Any], list[str])] | None) = None,
42
+ extract_globals_func: (Callable[([Any, ModuleType], dict[(str, Any)])] | None) = None
43
+ );
44
+
45
+ def compile_runtime_utils(self: ViteCompiler) -> tuple[str, list[str]];
46
+ def compile_dependencies_recursively(
47
+ self: ViteCompiler,
48
+ module_path: Path,
49
+ visited: (set[Path] | None) = None,
50
+ collected_exports: (set[str] | None) = None,
51
+ collected_globals: (dict[(str, Any)] | None) = None,
52
+ source_root: (Path | None) = None
53
+ ) -> None;
54
+
55
+ def _copy_js_file(self: ViteCompiler, js_path: Path, source_root: Path) -> None;
56
+ def _copy_ts_file(self: ViteCompiler, ts_path: Path, source_root: Path) -> None;
57
+ def _copy_asset_file(
58
+ self: ViteCompiler, asset_path: Path, source_root: Path
59
+ ) -> None;
60
+
61
+ def copy_root_assets(self: ViteCompiler) -> None;
62
+ def create_entry_file(self: ViteCompiler) -> None;
63
+ def compile_and_bundle(
64
+ self: ViteCompiler, module: ModuleType, module_path: Path
65
+ ) -> tuple[str, str, list[str], list[str]];
66
+ }
@@ -0,0 +1,32 @@
1
+ """Configuration loader for Jac Client build system.
2
+
3
+ This module provides configuration access for the client plugin.
4
+ Configuration is loaded from jac.toml under [plugins.client] section.
5
+
6
+ Inherits from PluginConfigBase to eliminate boilerplate code.
7
+ """
8
+ import from pathlib { Path }
9
+ import from typing { Any }
10
+ import from jaclang.project.plugin_config { PluginConfigBase }
11
+
12
+ """Client-specific configuration loader.
13
+
14
+ Provides access to vite, ts, and package configuration
15
+ from the [plugins.client] section of jac.toml.
16
+ """
17
+ class JacClientConfig(PluginConfigBase) {
18
+ override def get_plugin_name(self: JacClientConfig) -> str;
19
+ override def get_default_config(self: JacClientConfig) -> dict[str, Any];
20
+ override def load(self: JacClientConfig) -> dict[str, Any];
21
+ def save(self: JacClientConfig) -> None;
22
+ def get_vite_config(self: JacClientConfig) -> dict[str, Any];
23
+ def get_ts_config(self: JacClientConfig) -> dict[str, Any];
24
+ def get_package_config(self: JacClientConfig) -> dict[str, Any];
25
+ def add_dependency(
26
+ self: JacClientConfig, name: str, version: str, is_dev: bool = False
27
+ ) -> None;
28
+
29
+ def remove_dependency(
30
+ self: JacClientConfig, name: str, is_dev: bool = False
31
+ ) -> bool;
32
+ }
@@ -0,0 +1,127 @@
1
+ """Copy custom asset files (based on jac.toml configuration) from source to destination recursively."""
2
+
3
+ impl AssetProcessor.copy_custom_asset_types(
4
+ self: AssetProcessor,
5
+ src_dir: Path,
6
+ dest_dir: Path,
7
+ preserve_structure: bool = True
8
+ ) -> None {
9
+ if not src_dir.exists() {
10
+ return;
11
+ }
12
+ dest_dir.mkdir(parents=True, exist_ok=True);
13
+ def copy_recursive(
14
+ source: Path, destination: Path, base: (Path | None) = None
15
+ ) -> None {
16
+ if not source.exists() {
17
+ return;
18
+ }
19
+ if (base is None) {
20
+ base = source;
21
+ }
22
+ for item in source.iterdir() {
23
+ if (item.is_file() and (item.suffix.lower() in custom_asset_extensions)) {
24
+ if preserve_structure {
25
+ relative_path = item.relative_to(base);
26
+ dest_file = destination / relative_path;
27
+ } else {
28
+ dest_file = destination / item.name;
29
+ }
30
+ dest_file.parent.mkdir(parents=True, exist_ok=True);
31
+ with contextlib.suppress(OSError, shutil.Error) {
32
+ shutil.copy2(item, dest_file);
33
+ }
34
+ } elif item.is_dir() {
35
+ copy_recursive(item, destination, base);
36
+ }
37
+ }
38
+ }
39
+ config = get_config();
40
+ assets_config = config.get_plugin_config("client").get("assets", {});
41
+ custom_asset_extensions = set(assets_config.get("custom_extensions", []));
42
+ if custom_asset_extensions {
43
+ copy_recursive(src_dir, dest_dir);
44
+ }
45
+ return;
46
+ }
47
+
48
+ """Copy TypeScript files (.ts, .tsx) from source to destination recursively."""
49
+ impl AssetProcessor.copy_typescript_files(
50
+ self: AssetProcessor,
51
+ src_dir: Path,
52
+ dest_dir: Path,
53
+ preserve_structure: bool = True
54
+ ) -> None {
55
+ if not src_dir.exists() {
56
+ return;
57
+ }
58
+ dest_dir.mkdir(parents=True, exist_ok=True);
59
+ ts_extensions = {'.ts','.tsx'};
60
+ def copy_recursive(
61
+ source: Path, destination: Path, base: (Path | None) = None
62
+ ) -> None {
63
+ if not source.exists() {
64
+ return;
65
+ }
66
+ if (base is None) {
67
+ base = source;
68
+ }
69
+ for item in source.iterdir() {
70
+ if (item.is_file() and (item.suffix.lower() in ts_extensions)) {
71
+ if preserve_structure {
72
+ relative_path = item.relative_to(base);
73
+ dest_file = destination / relative_path;
74
+ } else {
75
+ dest_file = destination / item.name;
76
+ }
77
+ dest_file.parent.mkdir(parents=True, exist_ok=True);
78
+ with contextlib.suppress(OSError, shutil.Error) {
79
+ shutil.copy2(item, dest_file);
80
+ }
81
+ } elif item.is_dir() {
82
+ copy_recursive(item, destination, base);
83
+ }
84
+ }
85
+ }
86
+ copy_recursive(src_dir, dest_dir);
87
+ }
88
+
89
+ """Copy CSS and other asset files from source to destination recursively."""
90
+ impl AssetProcessor.copy_assets(
91
+ self: AssetProcessor,
92
+ src_dir: Path,
93
+ dest_dir: Path,
94
+ preserve_structure: bool = True
95
+ ) -> None {
96
+ if not src_dir.exists() {
97
+ return;
98
+ }
99
+ dest_dir.mkdir(parents=True, exist_ok=True);
100
+ def copy_recursive(
101
+ source: Path, destination: Path, base: (Path | None) = None
102
+ ) -> None {
103
+ if not source.exists() {
104
+ return;
105
+ }
106
+ if (base is None) {
107
+ base = source;
108
+ }
109
+ for item in source.iterdir() {
110
+ if (item.is_file() and (item.suffix.lower() in self.ASSET_EXTENSIONS)) {
111
+ if preserve_structure {
112
+ relative_path = item.relative_to(base);
113
+ dest_file = destination / relative_path;
114
+ } else {
115
+ dest_file = destination / item.name;
116
+ }
117
+ dest_file.parent.mkdir(parents=True, exist_ok=True);
118
+ with contextlib.suppress(OSError, shutil.Error) {
119
+ shutil.copy2(item, dest_file);
120
+ }
121
+ } elif item.is_dir() {
122
+ copy_recursive(item, destination, base);
123
+ }
124
+ }
125
+ }
126
+ copy_recursive(src_dir, dest_dir);
127
+ }
@@ -0,0 +1,84 @@
1
+ """Copy CSS, assets, and TypeScript files from compiled/ to build/ after Babel compilation."""
2
+
3
+ impl BabelProcessor.copy_assets_after_compile(
4
+ self: BabelProcessor,
5
+ compiled_dir: Path,
6
+ build_dir: Path,
7
+ asset_processor: AssetProcessor
8
+ ) -> None {
9
+ asset_processor.copy_assets(compiled_dir, build_dir);
10
+ asset_processor.copy_typescript_files(compiled_dir, build_dir);
11
+ }
12
+
13
+ """Run Babel compilation (npm run compile)."""
14
+ impl BabelProcessor.compile(self: BabelProcessor) -> None {
15
+ bundler = ViteBundler(self.project_dir);
16
+ # Ensure root package.json exists temporarily for npm commands
17
+ bundler._ensure_root_package_json();
18
+ try {
19
+ # Ensure dependencies are installed (check if node_modules exists)
20
+ build_dir = self.project_dir / '.client-build';
21
+ node_modules = build_dir / 'node_modules';
22
+ if not node_modules.exists() {
23
+ # Temporarily copy package.json to .client-build/ for npm install
24
+ build_package_json = build_dir / 'package.json';
25
+ configs_package_json = build_dir / '.jac-client.configs' / 'package.json';
26
+ if configs_package_json.exists() and not build_package_json.exists() {
27
+ import shutil;
28
+ shutil.copy2(configs_package_json, build_package_json);
29
+ }
30
+ try {
31
+ # Install to .client-build/node_modules
32
+ subprocess.run(
33
+ ['npm', 'install'],
34
+ cwd=build_dir,
35
+ check=True,
36
+ capture_output=True,
37
+ text=True
38
+ );
39
+ } except subprocess.CalledProcessError as e {
40
+ raise ClientBundleError(
41
+ f'Failed to install npm dependencies: {e.stderr}'
42
+ ) from e ;
43
+ } except FileNotFoundError {
44
+ raise ClientBundleError(
45
+ 'npm command not found. Ensure Node.js and npm are installed.'
46
+ ) from None ;
47
+ }
48
+ }
49
+
50
+ # Temporarily copy package.json to .client-build/ for npm run compile
51
+ build_package_json = build_dir / 'package.json';
52
+ configs_package_json = build_dir / '.jac-client.configs' / 'package.json';
53
+ if configs_package_json.exists() and not build_package_json.exists() {
54
+ import shutil;
55
+ shutil.copy2(configs_package_json, build_package_json);
56
+ }
57
+ command = ['npm', 'run', 'compile'];
58
+ subprocess.run(
59
+ command, cwd=build_dir, check=True, capture_output=True, text=True
60
+ );
61
+ } finally {
62
+ # Clean up temporary package.json in .client-build/
63
+ build_package_json = build_dir / 'package.json';
64
+ if build_package_json.exists() {
65
+ build_package_json.unlink();
66
+ }
67
+ # Move package-lock.json to .jac-client.configs/ if it exists
68
+ build_package_lock = build_dir / 'package-lock.json';
69
+ if build_package_lock.exists() {
70
+ configs_package_lock = build_dir / '.jac-client.configs' / 'package-lock.json';
71
+ if configs_package_lock.exists() {
72
+ configs_package_lock.unlink();
73
+ }
74
+ build_package_lock.rename(configs_package_lock);
75
+ }
76
+ # Always clean up root package.json and move package-lock.json
77
+ bundler._cleanup_root_package_files();
78
+ }
79
+ }
80
+
81
+ """Initialize the Babel processor."""
82
+ impl BabelProcessor.init(self: BabelProcessor, project_dir: Path) {
83
+ self.project_dir = project_dir;
84
+ }
@@ -0,0 +1,251 @@
1
+ """Compile module and dependencies, then bundle with Vite."""
2
+
3
+ impl ViteCompiler.compile_and_bundle(
4
+ self: ViteCompiler, module: ModuleType, module_path: Path
5
+ ) -> tuple[str, str, list[str], list[str]] {
6
+ self.compile_runtime_utils();
7
+ (module_js, mod, module_manifest) = self.jac_compiler.compile_module(module_path);
8
+ collected_exports: set[str] = set(
9
+ self.jac_compiler.extract_exports(module_manifest)
10
+ );
11
+ client_globals_map = self.jac_compiler.extract_globals(module_manifest, module);
12
+ collected_globals: dict[(str, Any)] = dict(client_globals_map);
13
+ self.compile_dependencies_recursively(
14
+ module_path,
15
+ collected_exports=collected_exports,
16
+ collected_globals=collected_globals
17
+ );
18
+ self.copy_root_assets();
19
+ self.create_entry_file();
20
+ self.babel_processor.compile();
21
+ self.babel_processor.copy_assets_after_compile(
22
+ self.compiled_dir,
23
+ (self.project_dir / '.client-build' / 'build'),
24
+ self.asset_processor
25
+ );
26
+ entry_file = self.project_dir / '.client-build' / 'build' / 'main.js';
27
+ self.vite_bundler.build(entry_file=entry_file);
28
+ (bundle_code, bundle_hash) = self.vite_bundler.read_bundle();
29
+ client_exports = sorted(collected_exports);
30
+ client_globals = list(collected_globals.keys());
31
+ return (bundle_code, bundle_hash, client_exports, client_globals);
32
+ }
33
+
34
+ """Create the main entry file for Vite bundling."""
35
+ impl ViteCompiler.create_entry_file(self: ViteCompiler) -> None {
36
+ entry_file = self.compiled_dir / 'main.js';
37
+ entry_content = 'import React from "react";\nimport { createRoot } from "react-dom/client";\nimport { app as App } from "./app.js";\n\nconst root = createRoot(document.getElementById("root"));\nroot.render(<App />);\n';
38
+ entry_file.write_text(entry_content, encoding='utf-8');
39
+ }
40
+
41
+ """Copy assets from root assets/ folder to compiled/assets/ for @jac-client/assets alias."""
42
+ impl ViteCompiler.copy_root_assets(self: ViteCompiler) -> None {
43
+ root_assets_dir = self.project_dir / 'assets';
44
+ compiled_assets_dir = self.compiled_dir / 'assets';
45
+ if (root_assets_dir.exists() and root_assets_dir.is_dir()) {
46
+ self.asset_processor.copy_assets(root_assets_dir, compiled_assets_dir);
47
+ }
48
+ # Copy configured_asset files from root assets/ to build assets/ (bypassing compiled)
49
+ build_assets_dir = self.project_dir / '.client-build' / 'build' / 'assets';
50
+ if (root_assets_dir.exists() and root_assets_dir.is_dir()) {
51
+ self.asset_processor.copy_custom_asset_types(root_assets_dir, build_assets_dir);
52
+ }
53
+ }
54
+
55
+ """Copy an asset file to the compiled directory."""
56
+ impl ViteCompiler._copy_asset_file(
57
+ self: ViteCompiler, asset_path: Path, source_root: Path
58
+ ) -> None {
59
+ if not asset_path.exists() {
60
+ return;
61
+ }
62
+ try {
63
+ relative_path = asset_path.relative_to(source_root);
64
+ output_path = self.compiled_dir / relative_path;
65
+ } except ValueError {
66
+ output_path = self.compiled_dir / asset_path.name;
67
+ }
68
+ output_path.parent.mkdir(parents=True, exist_ok=True);
69
+ with contextlib.suppress(FileNotFoundError, OSError) {
70
+ output_path.write_text(
71
+ asset_path.read_text(encoding='utf-8'), encoding='utf-8'
72
+ );
73
+ }
74
+ }
75
+
76
+ """Copy a TypeScript file to the compiled directory."""
77
+ impl ViteCompiler._copy_ts_file(
78
+ self: ViteCompiler, ts_path: Path, source_root: Path
79
+ ) -> None {
80
+ if not ts_path.exists() {
81
+ return;
82
+ }
83
+ try {
84
+ ts_code = ts_path.read_text(encoding='utf-8');
85
+ try {
86
+ relative_path = ts_path.relative_to(source_root);
87
+ output_path = self.compiled_dir / relative_path;
88
+ } except ValueError {
89
+ output_path = self.compiled_dir / ts_path.name;
90
+ }
91
+ output_path.parent.mkdir(parents=True, exist_ok=True);
92
+ output_path.write_text(ts_code, encoding='utf-8');
93
+ } except (FileNotFoundError, OSError) { }
94
+ }
95
+
96
+ """Copy a JavaScript file to the compiled directory."""
97
+ impl ViteCompiler._copy_js_file(
98
+ self: ViteCompiler, js_path: Path, source_root: Path
99
+ ) -> None {
100
+ try {
101
+ js_code = js_path.read_text(encoding='utf-8');
102
+ try {
103
+ relative_path = js_path.relative_to(source_root);
104
+ output_path = self.compiled_dir / relative_path;
105
+ } except ValueError {
106
+ output_path = self.compiled_dir / js_path.name;
107
+ }
108
+ output_path.parent.mkdir(parents=True, exist_ok=True);
109
+ output_path.write_text(js_code, encoding='utf-8');
110
+ } except FileNotFoundError { }
111
+ }
112
+
113
+ """Recursively compile/copy .jac/.js imports to temp, skipping bundling."""
114
+ impl ViteCompiler.compile_dependencies_recursively(
115
+ self: ViteCompiler,
116
+ module_path: Path,
117
+ visited: (set[Path] | None) = None,
118
+ collected_exports: (set[str] | None) = None,
119
+ collected_globals: (dict[(str, Any)] | None) = None,
120
+ source_root: (Path | None) = None
121
+ ) -> None {
122
+ if (visited is None) {
123
+ visited = set();
124
+ }
125
+ if (collected_exports is None) {
126
+ collected_exports = set();
127
+ }
128
+ if (collected_globals is None) {
129
+ collected_globals = {};
130
+ }
131
+ module_path = module_path.resolve();
132
+ if (module_path in visited) {
133
+ return;
134
+ }
135
+ visited.add(module_path);
136
+ if (source_root is None) {
137
+ source_root = module_path.parent.resolve();
138
+ }
139
+ (module_js, mod, manifest) = self.jac_compiler.compile_module(module_path);
140
+ exports_list = self.jac_compiler.extract_exports(manifest);
141
+ collected_exports.update(exports_list);
142
+ non_root_globals: dict[(str, Any)] = {};
143
+ if manifest {
144
+ for name in manifest.globals {
145
+ non_root_globals[name] = manifest.globals_values.get(name);
146
+ }
147
+ }
148
+ collected_globals.update(non_root_globals);
149
+ combined_js = self.jac_compiler.add_runtime_imports(module_js);
150
+ try {
151
+ relative_path = module_path.relative_to(source_root);
152
+ output_path = self.compiled_dir / relative_path.with_suffix('.js');
153
+ } except ValueError {
154
+ output_path = self.compiled_dir / f"{module_path.stem}.js";
155
+ }
156
+ output_path.parent.mkdir(parents=True, exist_ok=True);
157
+ output_path.write_text(combined_js, encoding='utf-8');
158
+ if (not manifest or not manifest.imports) {
159
+ return;
160
+ }
161
+ for (_name, import_path) in manifest.imports.items() {
162
+ path_obj = Path(import_path).resolve();
163
+ if (path_obj in visited) {
164
+ continue;
165
+ }
166
+ if (path_obj.suffix == '.jac') {
167
+ self.compile_dependencies_recursively(
168
+ path_obj,
169
+ visited,
170
+ collected_exports=collected_exports,
171
+ collected_globals=collected_globals,
172
+ source_root=source_root
173
+ );
174
+ } elif (path_obj.suffix == '.js') {
175
+ self._copy_js_file(path_obj, source_root);
176
+ } elif (path_obj.suffix in {'.ts','.tsx'}) {
177
+ self._copy_ts_file(path_obj, source_root);
178
+ } elif path_obj.is_file() {
179
+ self._copy_asset_file(path_obj, source_root);
180
+ }
181
+ }
182
+ }
183
+
184
+ """Compile client runtime utilities."""
185
+ impl ViteCompiler.compile_runtime_utils(self: ViteCompiler) -> tuple[str, list[str]] {
186
+ if not self.runtime_path {
187
+ raise ClientBundleError('Runtime path not set') ;
188
+ }
189
+ runtime_utils_path = self.runtime_path.parent / 'client_runtime.cl.jac';
190
+ (runtimeutils_js, mod, runtimeutils_manifest) = self.jac_compiler.compile_module(
191
+ runtime_utils_path
192
+ );
193
+ runtimeutils_exports_list = self.jac_compiler.extract_exports(
194
+ runtimeutils_manifest
195
+ );
196
+ all_exports = sorted(set((runtimeutils_exports_list + self.ROUTER_EXPORTS)));
197
+ combined_runtime_utils_js = runtimeutils_js;
198
+ self.compiled_dir.mkdir(parents=True, exist_ok=True);
199
+ (self.compiled_dir / 'client_runtime.js').write_text(
200
+ combined_runtime_utils_js, encoding='utf-8'
201
+ );
202
+ return (combined_runtime_utils_js, all_exports);
203
+ }
204
+
205
+ """Initialize the Vite compiler."""
206
+ impl ViteCompiler.init(
207
+ self: ViteCompiler,
208
+ vite_package_json: Path,
209
+ vite_output_dir: (Path | None) = None,
210
+ vite_minify: bool = False,
211
+ runtime_path: (Path | None) = None,
212
+ compile_to_js_func: (Callable[([Path], tuple[(str, (ModuleType | None))])] | None) = None,
213
+ extract_exports_func: (Callable[([Any], list[str])] | None) = None,
214
+ extract_globals_func: (Callable[([Any, ModuleType], dict[(str, Any)])] | None) = None
215
+ ) {
216
+ if (not vite_package_json or not vite_package_json.exists()) {
217
+ raise ClientBundleError(
218
+ 'Vite package.json not found. Set vite_package_json when using ViteCompiler'
219
+ ) ;
220
+ }
221
+ if (
222
+ (compile_to_js_func is None)
223
+ or (extract_exports_func is None)
224
+ or (extract_globals_func is None)
225
+ ) {
226
+ raise ClientBundleError(
227
+ 'compile_to_js_func, extract_exports_func, and extract_globals_func are required'
228
+ ) ;
229
+ }
230
+ self.vite_package_json = vite_package_json;
231
+ # If package.json is in .client-build/.jac-client.configs/, go up two levels to get project root
232
+ if (
233
+ vite_package_json.parent.name == '.jac-client.configs'
234
+ and vite_package_json.parent.parent.name == '.client-build'
235
+ ) {
236
+ self.project_dir = vite_package_json.parent.parent.parent;
237
+ } elif (vite_package_json.parent.name == '.jac-client.configs') {
238
+ self.project_dir = vite_package_json.parent.parent;
239
+ } else {
240
+ self.project_dir = vite_package_json.parent;
241
+ }
242
+ self.runtime_path = runtime_path;
243
+ self.compiled_dir = self.project_dir / '.client-build' / 'compiled';
244
+ self.jac_compiler = JacToJSCompiler(
245
+ compile_to_js_func, extract_exports_func, extract_globals_func
246
+ );
247
+ self.import_processor = ImportProcessor();
248
+ self.asset_processor = AssetProcessor();
249
+ self.babel_processor = BabelProcessor(self.project_dir);
250
+ self.vite_bundler = ViteBundler(self.project_dir, vite_output_dir, vite_minify);
251
+ }
@@ -0,0 +1,119 @@
1
+ """Implementation of Jac Client configuration loader.
2
+
3
+ This module provides the implementation for JacClientConfig, which inherits
4
+ from PluginConfigBase for common configuration loading functionality.
5
+
6
+ The base class handles: init, get_jac_config, get_section.
7
+ This file implements plugin-specific methods including a custom load()
8
+ that combines plugin config with npm dependencies.
9
+ """
10
+ import from pathlib { Path }
11
+ import from typing { Any }
12
+ import from jaclang.project.plugin_config { deep_merge }
13
+
14
+ """Get the plugin section name for client."""
15
+ impl JacClientConfig.get_plugin_name(self: JacClientConfig) -> str {
16
+ return "client";
17
+ }
18
+
19
+ """Get default configuration structure for client."""
20
+ impl JacClientConfig.get_default_config(self: JacClientConfig) -> dict[str, Any] {
21
+ return {
22
+ 'vite': {
23
+ 'plugins': [],
24
+ 'lib_imports': [],
25
+ 'build': {},
26
+ 'server': {},
27
+ 'resolve': {}
28
+ },
29
+ 'ts': {'compilerOptions': {}, 'include': [], 'exclude': []},
30
+ 'package': {
31
+ 'name': '',
32
+ 'version': '1.0.0',
33
+ 'description': '',
34
+ 'dependencies': {},
35
+ 'devDependencies': {}
36
+ }
37
+ };
38
+ }
39
+
40
+ """Load configuration from jac.toml, merging with defaults.
41
+
42
+ Overrides base class to also include npm dependencies from [dependencies.npm].
43
+ """
44
+ impl JacClientConfig.load(self: JacClientConfig) -> dict[str, Any] {
45
+ if self._config is not None {
46
+ return self._config;
47
+ }
48
+ default_config = self.get_default_config();
49
+ jac_config = self.get_jac_config();
50
+ # Get client plugin config from [plugins.client]
51
+ client_config = jac_config.get_plugin_config('client');
52
+ # Get npm dependencies from [dependencies.npm]
53
+ npm_deps = jac_config.get_plugin_deps('npm');
54
+ # Get npm dev dependencies from [dev-dependencies.npm]
55
+ # These are stored in plugin_dependencies["npm"]["dev"] after parsing
56
+ npm_plugin_deps = jac_config.plugin_dependencies.get('npm', {});
57
+ npm_dev_deps = npm_plugin_deps.get('dev', {})
58
+ if isinstance(npm_plugin_deps.get('dev'), dict)
59
+ else {};
60
+ # Build user config in the expected internal format
61
+ user_config: dict[str, Any] = {
62
+ 'vite': client_config.get('vite', {}),
63
+ 'ts': client_config.get('ts', {}),
64
+ 'package': {
65
+ 'name': jac_config.project.name,
66
+ 'version': jac_config.project.version,
67
+ 'description': jac_config.project.description,
68
+ 'dependencies': npm_deps,
69
+ 'devDependencies': npm_dev_deps
70
+ }
71
+ };
72
+ self._config = deep_merge(default_config, user_config);
73
+ return self._config;
74
+ }
75
+
76
+ """Get package configuration (npm dependencies)."""
77
+ impl JacClientConfig.get_package_config(self: JacClientConfig) -> dict[str, Any] {
78
+ config = self.load();
79
+ return config.get('package', {});
80
+ }
81
+
82
+ """Get Vite-specific configuration."""
83
+ impl JacClientConfig.get_vite_config(self: JacClientConfig) -> dict[str, Any] {
84
+ config = self.load();
85
+ return config.get('vite', {});
86
+ }
87
+
88
+ """Get TypeScript-specific configuration for tsconfig.json customization."""
89
+ impl JacClientConfig.get_ts_config(self: JacClientConfig) -> dict[str, Any] {
90
+ config = self.load();
91
+ return config.get('ts', {});
92
+ }
93
+
94
+ """Save configuration back to jac.toml using core JacConfig."""
95
+ impl JacClientConfig.save(self: JacClientConfig) -> None {
96
+ jac_config = self.get_jac_config();
97
+ jac_config.save();
98
+ }
99
+
100
+ """Add an npm dependency."""
101
+ impl JacClientConfig.add_dependency(
102
+ self: JacClientConfig, name: str, version: str, is_dev: bool = False
103
+ ) -> None {
104
+ jac_config = self.get_jac_config();
105
+ jac_config.add_dependency(name, version, dev=is_dev, dep_type="npm");
106
+ # Invalidate cache
107
+ self.invalidate();
108
+ }
109
+
110
+ """Remove an npm dependency."""
111
+ impl JacClientConfig.remove_dependency(
112
+ self: JacClientConfig, name: str, is_dev: bool = False
113
+ ) -> bool {
114
+ jac_config = self.get_jac_config();
115
+ result = jac_config.remove_dependency(name, dev=is_dev, dep_type="npm");
116
+ # Invalidate cache
117
+ self.invalidate();
118
+ return result;
119
+ }