rpr-cli 0.1.1__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.
- rpr/__init__.py +1 -0
- rpr/agent/__init__.py +29 -0
- rpr/agent/approval.py +19 -0
- rpr/agent/bootstrap.py +60 -0
- rpr/agent/client.py +115 -0
- rpr/agent/control.py +16 -0
- rpr/agent/mock.py +158 -0
- rpr/agent/runtime.py +291 -0
- rpr/agent/session.py +91 -0
- rpr/agent/tools/__init__.py +10 -0
- rpr/agent/tools/base.py +62 -0
- rpr/agent/tools/mutating.py +47 -0
- rpr/agent/tools/readonly.py +147 -0
- rpr/agent/tools/registry.py +30 -0
- rpr/application/__init__.py +1 -0
- rpr/application/catalog.py +427 -0
- rpr/application/chat_service.py +413 -0
- rpr/application/checks.py +49 -0
- rpr/application/cli_adapter.py +36 -0
- rpr/application/completer.py +163 -0
- rpr/application/conversation_service.py +92 -0
- rpr/application/prompt_service.py +85 -0
- rpr/application/selector.py +240 -0
- rpr/application/shell.py +543 -0
- rpr/checks/__init__.py +0 -0
- rpr/checks/base.py +13 -0
- rpr/checks/instructions.py +89 -0
- rpr/checks/packages.py +619 -0
- rpr/checks/workspace.py +170 -0
- rpr/cli.py +78 -0
- rpr/commands/__init__.py +0 -0
- rpr/commands/add.py +166 -0
- rpr/commands/chat.py +48 -0
- rpr/commands/check.py +53 -0
- rpr/commands/generate/__init__.py +0 -0
- rpr/commands/generate/api.py +228 -0
- rpr/commands/generate/domain.py +383 -0
- rpr/commands/generate/engine.py +148 -0
- rpr/commands/generate/storybook.py +442 -0
- rpr/commands/generate/ui.py +414 -0
- rpr/commands/init.py +822 -0
- rpr/commands/map.py +113 -0
- rpr/commands/settings.py +102 -0
- rpr/commands/sync.py +97 -0
- rpr/context.py +203 -0
- rpr/generators/__init__.py +0 -0
- rpr/generators/base.py +110 -0
- rpr/generators/claude.py +33 -0
- rpr/generators/copilot.py +36 -0
- rpr/generators/cursor.py +38 -0
- rpr/generators/gemini.py +33 -0
- rpr/map/__init__.py +0 -0
- rpr/map/architecture.py +495 -0
- rpr/map/chains.py +317 -0
- rpr/map/classifier.py +170 -0
- rpr/map/coverage.py +200 -0
- rpr/map/dependencies.py +243 -0
- rpr/map/extractor.py +223 -0
- rpr/map/graph.py +318 -0
- rpr/map/output.py +1030 -0
- rpr/map/responsibility.py +345 -0
- rpr/map/topology.py +327 -0
- rpr/map/walker.py +151 -0
- rpr/scaffolds/domain/base_entity.md +30 -0
- rpr/scaffolds/domain/base_repo.md +48 -0
- rpr/scaffolds/domain/container.md +76 -0
- rpr/scaffolds/domain/settings.md +57 -0
- rpr/scaffolds/instructions/all.instructions.md +50 -0
- rpr/scaffolds/instructions/api.instructions.md +42 -0
- rpr/scaffolds/instructions/domain.instructions.md +93 -0
- rpr/scaffolds/instructions/frontend.instructions.md +97 -0
- rpr/scaffolds/instructions/rust-engine.instructions.md +40 -0
- rpr/scaffolds/instructions/setup-guide.instructions.md +86 -0
- rpr/scaffolds/instructions/tooling-setup.instructions.md +97 -0
- rpr/scaffolds/instructions/tooling.instructions.md +42 -0
- rpr/scaffolds/js_special_files/fetch.service.md +222 -0
- rpr/scaffolds/js_special_files/sticky-navigation.md +164 -0
- rpr/scaffolds/special_files/domain_container.md +76 -0
- rpr/scaffolds/special_files/domain_settings.md +57 -0
- rpr/scaffolds/special_files/dto_util.md +62 -0
- rpr/scaffolds/special_files/encrypted_column.md +98 -0
- rpr/scaffolds/special_files/mapper_util.md +159 -0
- rpr/scaffolds/special_files/partial_update.md +61 -0
- rpr/templates/__init__.py +0 -0
- rpr/templates/registry.py +81 -0
- rpr/ui/__init__.py +0 -0
- rpr/ui/console.py +32 -0
- rpr/ui/markdown.py +59 -0
- rpr/ui/prompt_session.py +430 -0
- rpr/ui/renderers.py +167 -0
- rpr/ui/theme.py +286 -0
- rpr/workspace.py +131 -0
- rpr_cli-0.1.1.dist-info/METADATA +201 -0
- rpr_cli-0.1.1.dist-info/RECORD +97 -0
- rpr_cli-0.1.1.dist-info/WHEEL +4 -0
- rpr_cli-0.1.1.dist-info/entry_points.txt +2 -0
- rpr_cli-0.1.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Annotated
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
|
|
10
|
+
from rpr.cli import generate_app
|
|
11
|
+
from rpr.context import RunContext
|
|
12
|
+
from rpr.workspace import add_workspace_member
|
|
13
|
+
|
|
14
|
+
console = Console()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@generate_app.command()
|
|
18
|
+
def engine(
|
|
19
|
+
name: Annotated[
|
|
20
|
+
str | None, typer.Argument(help="App name (used as package prefix).")
|
|
21
|
+
] = None,
|
|
22
|
+
dry_run: Annotated[
|
|
23
|
+
bool, typer.Option("--dry-run", help="Preview changes without writing.")
|
|
24
|
+
] = False,
|
|
25
|
+
) -> None:
|
|
26
|
+
"""Scaffold a Rust + PyO3 engine package."""
|
|
27
|
+
if not name:
|
|
28
|
+
name = typer.prompt("App name")
|
|
29
|
+
|
|
30
|
+
ctx = RunContext(dry_run=dry_run, project_dir=Path.cwd())
|
|
31
|
+
engine_name = f"{name}-engine"
|
|
32
|
+
engine_underscore = f"{name.replace('-', '_')}_engine"
|
|
33
|
+
engine_root = ctx.project_dir / "packages" / "python" / engine_name
|
|
34
|
+
|
|
35
|
+
console.print(f"\n[bold]Generating Rust/PyO3 engine:[/] {engine_name}\n")
|
|
36
|
+
|
|
37
|
+
ctx.ensure_dir(engine_root / "src")
|
|
38
|
+
|
|
39
|
+
_write_cargo_toml(ctx, engine_root, engine_name, engine_underscore)
|
|
40
|
+
_write_lib_rs(ctx, engine_root / "src" / "lib.rs", engine_underscore)
|
|
41
|
+
_write_engine_pyproject(ctx, engine_root, engine_name, engine_underscore)
|
|
42
|
+
_write_pyi_stub(ctx, engine_root / f"{engine_underscore}.pyi", engine_underscore)
|
|
43
|
+
_write_engine_project_json(ctx, engine_root, engine_name)
|
|
44
|
+
|
|
45
|
+
add_workspace_member(ctx, f"packages/python/{engine_name}")
|
|
46
|
+
ctx.preview_dependencies(
|
|
47
|
+
manager="uv",
|
|
48
|
+
target=f"packages/python/{engine_name}",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
if not dry_run:
|
|
52
|
+
ctx.run_command(["uv", "sync"], cwd=ctx.project_dir)
|
|
53
|
+
|
|
54
|
+
console.print(f"\n[bold green]Done![/] Rust engine created at {engine_root}")
|
|
55
|
+
console.print(f" Build with: npx nx engine:build {engine_name}")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _write_cargo_toml(
|
|
59
|
+
ctx: RunContext, engine_root: Path, engine_name: str, engine_underscore: str
|
|
60
|
+
) -> None:
|
|
61
|
+
content = f"""[package]
|
|
62
|
+
name = "{engine_name}"
|
|
63
|
+
version = "0.1.0"
|
|
64
|
+
edition = "2021"
|
|
65
|
+
|
|
66
|
+
[lib]
|
|
67
|
+
name = "{engine_underscore}"
|
|
68
|
+
crate-type = ["cdylib"]
|
|
69
|
+
|
|
70
|
+
[dependencies]
|
|
71
|
+
pyo3 = {{ version = "0.21", features = ["extension-module"] }}
|
|
72
|
+
"""
|
|
73
|
+
ctx.write_file(engine_root / "Cargo.toml", content)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _write_lib_rs(ctx: RunContext, path: Path, engine_underscore: str) -> None:
|
|
77
|
+
content = f"""use pyo3::prelude::*;
|
|
78
|
+
|
|
79
|
+
#[pyfunction]
|
|
80
|
+
fn hello() -> PyResult<String> {{
|
|
81
|
+
Ok("hello from {engine_underscore}".to_string())
|
|
82
|
+
}}
|
|
83
|
+
|
|
84
|
+
#[pymodule]
|
|
85
|
+
fn {engine_underscore}(m: &Bound<'_, PyModule>) -> PyResult<()> {{
|
|
86
|
+
m.add_function(wrap_pyfunction!(hello, m)?)?;
|
|
87
|
+
Ok(())
|
|
88
|
+
}}
|
|
89
|
+
"""
|
|
90
|
+
ctx.write_file(path, content)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _write_engine_pyproject(
|
|
94
|
+
ctx: RunContext, engine_root: Path, engine_name: str, engine_underscore: str
|
|
95
|
+
) -> None:
|
|
96
|
+
content = f"""[build-system]
|
|
97
|
+
requires = ["maturin>=1.8.2,<2.0"]
|
|
98
|
+
build-backend = "maturin"
|
|
99
|
+
|
|
100
|
+
[project]
|
|
101
|
+
name = "{engine_name}"
|
|
102
|
+
version = "0.1.0"
|
|
103
|
+
requires-python = ">=3.12"
|
|
104
|
+
|
|
105
|
+
[tool.maturin]
|
|
106
|
+
features = ["pyo3/extension-module"]
|
|
107
|
+
module-name = "{engine_underscore}"
|
|
108
|
+
"""
|
|
109
|
+
ctx.write_file(engine_root / "pyproject.toml", content)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _write_pyi_stub(ctx: RunContext, path: Path, engine_underscore: str) -> None:
|
|
113
|
+
content = """def hello() -> str: ...
|
|
114
|
+
"""
|
|
115
|
+
ctx.write_file(path, content)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _write_engine_project_json(
|
|
119
|
+
ctx: RunContext, engine_root: Path, engine_name: str
|
|
120
|
+
) -> None:
|
|
121
|
+
project = {
|
|
122
|
+
"name": engine_name,
|
|
123
|
+
"root": f"packages/python/{engine_name}",
|
|
124
|
+
"targets": {
|
|
125
|
+
"engine:build": {
|
|
126
|
+
"executor": "nx:run-commands",
|
|
127
|
+
"options": {
|
|
128
|
+
"command": "uv run maturin develop",
|
|
129
|
+
"cwd": f"packages/python/{engine_name}",
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
"engine:lint": {
|
|
133
|
+
"executor": "nx:run-commands",
|
|
134
|
+
"options": {
|
|
135
|
+
"command": "cargo clippy --all-targets --all-features -- -D warnings",
|
|
136
|
+
"cwd": f"packages/python/{engine_name}",
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
"engine:format": {
|
|
140
|
+
"executor": "nx:run-commands",
|
|
141
|
+
"options": {
|
|
142
|
+
"command": "cargo fmt --check",
|
|
143
|
+
"cwd": f"packages/python/{engine_name}",
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
}
|
|
148
|
+
ctx.write_file(engine_root / "project.json", json.dumps(project, indent=2) + "\n")
|
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Annotated
|
|
6
|
+
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
|
|
10
|
+
from rpr.cli import generate_app
|
|
11
|
+
from rpr.context import RunContext
|
|
12
|
+
from rpr.workspace import ensure_npm_workspaces, write_package_json
|
|
13
|
+
|
|
14
|
+
console = Console()
|
|
15
|
+
_NO_UI_LIBRARY_ERROR = (
|
|
16
|
+
"[rpr] Error: No UI library found at packages/node/*-ui/. "
|
|
17
|
+
"Run `rpr generate ui <name>` first."
|
|
18
|
+
)
|
|
19
|
+
_ROOT_STORYBOOK_DEV_DEPENDENCIES = {
|
|
20
|
+
"@nx/storybook": "latest",
|
|
21
|
+
}
|
|
22
|
+
_STORYBOOK_DEPENDENCIES = {
|
|
23
|
+
"@emotion/react": "^11",
|
|
24
|
+
"@emotion/styled": "^11",
|
|
25
|
+
"@mui/material": "^6",
|
|
26
|
+
"react": "^19",
|
|
27
|
+
"react-dom": "^19",
|
|
28
|
+
}
|
|
29
|
+
_STORYBOOK_DEV_DEPENDENCIES = {
|
|
30
|
+
"@storybook/addon-essentials": "^8",
|
|
31
|
+
"@storybook/react": "^8",
|
|
32
|
+
"@storybook/react-vite": "^8",
|
|
33
|
+
"@types/react": "^19",
|
|
34
|
+
"@types/react-dom": "^19",
|
|
35
|
+
"storybook": "^8",
|
|
36
|
+
"typescript": "^5",
|
|
37
|
+
"vite": "^6",
|
|
38
|
+
"vitest": "^3",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _storybook_package_dependencies(ui_pkg: str) -> dict[str, str]:
|
|
43
|
+
return {
|
|
44
|
+
f"@repo/{ui_pkg}": "workspace:*",
|
|
45
|
+
**_STORYBOOK_DEPENDENCIES,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _find_ui_packages(project_dir: Path) -> list[str]:
|
|
50
|
+
"""Return UI packages that look like real Nx/UI libraries."""
|
|
51
|
+
node_packages = project_dir / "packages" / "node"
|
|
52
|
+
if not node_packages.exists():
|
|
53
|
+
return []
|
|
54
|
+
|
|
55
|
+
matches: list[str] = []
|
|
56
|
+
for child in sorted(node_packages.iterdir(), key=lambda path: path.name):
|
|
57
|
+
if not child.is_dir() or not child.name.endswith("-ui"):
|
|
58
|
+
continue
|
|
59
|
+
if (child / "project.json").exists() or (child / "package.json").exists():
|
|
60
|
+
matches.append(child.name)
|
|
61
|
+
return matches
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _choose_ui_package(ui_packages: list[str]) -> str:
|
|
65
|
+
if len(ui_packages) == 1:
|
|
66
|
+
return ui_packages[0]
|
|
67
|
+
|
|
68
|
+
console.print(
|
|
69
|
+
"\n[bold]Multiple UI libraries found.[/] Choose a Storybook target:\n"
|
|
70
|
+
)
|
|
71
|
+
for index, ui_package in enumerate(ui_packages, start=1):
|
|
72
|
+
console.print(f" {index}. {ui_package}")
|
|
73
|
+
|
|
74
|
+
allowed_choices = ", ".join(ui_packages)
|
|
75
|
+
while True:
|
|
76
|
+
raw_selection = typer.prompt("Choose UI library", default="1")
|
|
77
|
+
selection = str(raw_selection).strip()
|
|
78
|
+
if selection.isdigit():
|
|
79
|
+
choice_index = int(selection)
|
|
80
|
+
if 1 <= choice_index <= len(ui_packages):
|
|
81
|
+
return ui_packages[choice_index - 1]
|
|
82
|
+
if selection in ui_packages:
|
|
83
|
+
return selection
|
|
84
|
+
|
|
85
|
+
console.print(
|
|
86
|
+
f"[bold red]Error:[/] Invalid choice '{selection}'. "
|
|
87
|
+
f"Enter 1-{len(ui_packages)} or one of: {allowed_choices}"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@generate_app.command()
|
|
92
|
+
def storybook(
|
|
93
|
+
ui_package: Annotated[
|
|
94
|
+
str | None,
|
|
95
|
+
typer.Option(
|
|
96
|
+
"--ui-package", help="UI package to target when multiple libraries exist."
|
|
97
|
+
),
|
|
98
|
+
] = None,
|
|
99
|
+
dry_run: Annotated[
|
|
100
|
+
bool, typer.Option("--dry-run", help="Preview changes without writing.")
|
|
101
|
+
] = False,
|
|
102
|
+
) -> None:
|
|
103
|
+
"""Add a Storybook package for the UI library."""
|
|
104
|
+
ctx = RunContext(dry_run=dry_run, project_dir=Path.cwd())
|
|
105
|
+
|
|
106
|
+
ui_packages = _find_ui_packages(ctx.project_dir)
|
|
107
|
+
if not ui_packages:
|
|
108
|
+
typer.echo(_NO_UI_LIBRARY_ERROR)
|
|
109
|
+
raise typer.Exit(1)
|
|
110
|
+
|
|
111
|
+
if ui_package is not None:
|
|
112
|
+
if ui_package not in ui_packages:
|
|
113
|
+
allowed = ", ".join(ui_packages)
|
|
114
|
+
typer.echo(
|
|
115
|
+
f"[rpr] Error: Unknown UI package '{ui_package}'. Valid: {allowed}"
|
|
116
|
+
)
|
|
117
|
+
raise typer.Exit(1)
|
|
118
|
+
ui_pkg = ui_package
|
|
119
|
+
else:
|
|
120
|
+
ui_pkg = _choose_ui_package(ui_packages)
|
|
121
|
+
sb_root = ctx.project_dir / "packages" / "node" / "sb"
|
|
122
|
+
|
|
123
|
+
console.print(
|
|
124
|
+
f"\n[bold]Generating Storybook package:[/] sb (importing from {ui_pkg})\n"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
ensure_npm_workspaces(ctx, package_name=ctx.project_dir.name)
|
|
128
|
+
_write_root_storybook_dependency(ctx)
|
|
129
|
+
|
|
130
|
+
storybook_dir = sb_root / ".storybook"
|
|
131
|
+
src_root = sb_root / "src"
|
|
132
|
+
starter_story = (
|
|
133
|
+
ctx.project_dir
|
|
134
|
+
/ "packages"
|
|
135
|
+
/ "node"
|
|
136
|
+
/ ui_pkg
|
|
137
|
+
/ "src"
|
|
138
|
+
/ "stories"
|
|
139
|
+
/ "Example.stories.tsx"
|
|
140
|
+
)
|
|
141
|
+
ctx.ensure_dir(storybook_dir)
|
|
142
|
+
ctx.ensure_dir(src_root)
|
|
143
|
+
ctx.ensure_dir(starter_story.parent)
|
|
144
|
+
|
|
145
|
+
_write_sb_package_json(ctx, sb_root, ui_pkg)
|
|
146
|
+
_write_sb_project_json(ctx, sb_root)
|
|
147
|
+
_write_sb_tsconfig(ctx, sb_root)
|
|
148
|
+
_write_sb_eslint_config(ctx, sb_root)
|
|
149
|
+
_write_sb_index_html(ctx, sb_root)
|
|
150
|
+
_write_sb_main_tsx(ctx, src_root)
|
|
151
|
+
_write_sb_app(ctx, src_root, ui_pkg)
|
|
152
|
+
_write_sb_app_test(ctx, src_root, ui_pkg)
|
|
153
|
+
_write_sb_vite_config(ctx, sb_root)
|
|
154
|
+
_write_sb_main(ctx, storybook_dir / "main.ts", ui_pkg)
|
|
155
|
+
_write_sb_preview(ctx, storybook_dir / "preview.ts")
|
|
156
|
+
_write_example_story(ctx, starter_story, ui_pkg)
|
|
157
|
+
|
|
158
|
+
ctx.preview_dependencies(
|
|
159
|
+
manager="npm",
|
|
160
|
+
target="workspace root",
|
|
161
|
+
dev=list(_ROOT_STORYBOOK_DEV_DEPENDENCIES),
|
|
162
|
+
)
|
|
163
|
+
ctx.preview_dependencies(
|
|
164
|
+
manager="npm",
|
|
165
|
+
target="packages/node/sb",
|
|
166
|
+
runtime=list(_storybook_package_dependencies(ui_pkg)),
|
|
167
|
+
dev=list(_STORYBOOK_DEV_DEPENDENCIES),
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
if not dry_run:
|
|
171
|
+
ctx.run_command(["npm", "install"], cwd=ctx.project_dir)
|
|
172
|
+
|
|
173
|
+
ctx.run_command(
|
|
174
|
+
[
|
|
175
|
+
"npx",
|
|
176
|
+
"nx",
|
|
177
|
+
"g",
|
|
178
|
+
"@nx/storybook:configuration",
|
|
179
|
+
"--project=sb",
|
|
180
|
+
"--uiFramework=@storybook/react-vite",
|
|
181
|
+
"--interactionTests=true",
|
|
182
|
+
],
|
|
183
|
+
cwd=ctx.project_dir,
|
|
184
|
+
supports_dry_run=True,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
console.print(f"\n[bold green]Done![/] Storybook created at {sb_root}")
|
|
188
|
+
console.print(" Run with: npx nx storybook sb")
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _write_root_storybook_dependency(ctx: RunContext) -> None:
|
|
192
|
+
write_package_json(
|
|
193
|
+
ctx,
|
|
194
|
+
ctx.project_dir / "package.json",
|
|
195
|
+
defaults={
|
|
196
|
+
"name": ctx.project_dir.name,
|
|
197
|
+
"private": True,
|
|
198
|
+
},
|
|
199
|
+
dev_dependencies=_ROOT_STORYBOOK_DEV_DEPENDENCIES,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _write_sb_package_json(ctx: RunContext, sb_root: Path, ui_pkg: str) -> None:
|
|
204
|
+
write_package_json(
|
|
205
|
+
ctx,
|
|
206
|
+
sb_root / "package.json",
|
|
207
|
+
defaults={
|
|
208
|
+
"name": "@repo/sb",
|
|
209
|
+
"version": "0.1.0",
|
|
210
|
+
"private": True,
|
|
211
|
+
"type": "module",
|
|
212
|
+
},
|
|
213
|
+
dependencies=_storybook_package_dependencies(ui_pkg),
|
|
214
|
+
dev_dependencies=_STORYBOOK_DEV_DEPENDENCIES,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _write_sb_project_json(ctx: RunContext, sb_root: Path) -> None:
|
|
219
|
+
project = {
|
|
220
|
+
"name": "sb",
|
|
221
|
+
"root": "packages/node/sb",
|
|
222
|
+
"targets": {
|
|
223
|
+
"serve": {
|
|
224
|
+
"executor": "nx:run-commands",
|
|
225
|
+
"options": {
|
|
226
|
+
"command": "npx vite",
|
|
227
|
+
"cwd": "packages/node/sb",
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
"build": {
|
|
231
|
+
"executor": "nx:run-commands",
|
|
232
|
+
"options": {
|
|
233
|
+
"command": "npx vite build",
|
|
234
|
+
"cwd": "packages/node/sb",
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
"lint": {
|
|
238
|
+
"executor": "nx:run-commands",
|
|
239
|
+
"options": {
|
|
240
|
+
"command": "npx eslint .",
|
|
241
|
+
"cwd": "packages/node/sb",
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
"test": {
|
|
245
|
+
"executor": "nx:run-commands",
|
|
246
|
+
"options": {
|
|
247
|
+
"command": "npx vitest run",
|
|
248
|
+
"cwd": "packages/node/sb",
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
"typecheck": {
|
|
252
|
+
"executor": "nx:run-commands",
|
|
253
|
+
"options": {
|
|
254
|
+
"command": "npx tsc --noEmit",
|
|
255
|
+
"cwd": "packages/node/sb",
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
"storybook": {
|
|
259
|
+
"executor": "nx:run-commands",
|
|
260
|
+
"options": {
|
|
261
|
+
"command": "storybook dev -p 6006 -c packages/node/sb/.storybook",
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
"build-storybook": {
|
|
265
|
+
"executor": "nx:run-commands",
|
|
266
|
+
"options": {
|
|
267
|
+
"command": "storybook build -c packages/node/sb/.storybook -o dist/storybook",
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
}
|
|
272
|
+
ctx.write_file(sb_root / "project.json", json.dumps(project, indent=2) + "\n")
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _write_sb_tsconfig(ctx: RunContext, sb_root: Path) -> None:
|
|
276
|
+
content = """{
|
|
277
|
+
"extends": "../../../tsconfig.base.json",
|
|
278
|
+
"compilerOptions": {
|
|
279
|
+
"jsx": "react-jsx",
|
|
280
|
+
"outDir": "dist",
|
|
281
|
+
"rootDir": "src"
|
|
282
|
+
},
|
|
283
|
+
"include": ["src", ".storybook"]
|
|
284
|
+
}
|
|
285
|
+
"""
|
|
286
|
+
ctx.write_file(sb_root / "tsconfig.json", content)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def _write_sb_eslint_config(ctx: RunContext, sb_root: Path) -> None:
|
|
290
|
+
content = """import baseConfig from "../../../eslint.config.mjs";
|
|
291
|
+
|
|
292
|
+
export default [...baseConfig];
|
|
293
|
+
"""
|
|
294
|
+
ctx.write_file(sb_root / "eslint.config.mjs", content)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def _write_sb_index_html(ctx: RunContext, sb_root: Path) -> None:
|
|
298
|
+
content = """<!DOCTYPE html>
|
|
299
|
+
<html lang="en">
|
|
300
|
+
<head>
|
|
301
|
+
<meta charset="UTF-8" />
|
|
302
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
303
|
+
<title>Storybook Host</title>
|
|
304
|
+
</head>
|
|
305
|
+
<body>
|
|
306
|
+
<div id="root"></div>
|
|
307
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
308
|
+
</body>
|
|
309
|
+
</html>
|
|
310
|
+
"""
|
|
311
|
+
ctx.write_file(sb_root / "index.html", content)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def _write_sb_main_tsx(ctx: RunContext, src_root: Path) -> None:
|
|
315
|
+
content = """import React from "react";
|
|
316
|
+
import ReactDOM from "react-dom/client";
|
|
317
|
+
import { App } from "./App";
|
|
318
|
+
|
|
319
|
+
ReactDOM.createRoot(document.getElementById("root")!).render(
|
|
320
|
+
<React.StrictMode>
|
|
321
|
+
<App />
|
|
322
|
+
</React.StrictMode>,
|
|
323
|
+
);
|
|
324
|
+
"""
|
|
325
|
+
ctx.write_file(src_root / "main.tsx", content)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def _write_sb_app(ctx: RunContext, src_root: Path, ui_pkg: str) -> None:
|
|
329
|
+
content = f"""import {{ uiPackageName }} from "@repo/{ui_pkg}";
|
|
330
|
+
|
|
331
|
+
export const storybookHostTitle = "Storybook Host";
|
|
332
|
+
|
|
333
|
+
export const App = () => {{
|
|
334
|
+
return (
|
|
335
|
+
<div>
|
|
336
|
+
<h1>{{storybookHostTitle}}</h1>
|
|
337
|
+
<p>Rendering stories from {{uiPackageName}}</p>
|
|
338
|
+
</div>
|
|
339
|
+
);
|
|
340
|
+
}};
|
|
341
|
+
"""
|
|
342
|
+
ctx.write_file(src_root / "App.tsx", content)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def _write_sb_app_test(ctx: RunContext, src_root: Path, ui_pkg: str) -> None:
|
|
346
|
+
content = """import { describe, expect, it } from "vitest";
|
|
347
|
+
|
|
348
|
+
import { storybookHostTitle } from "./App";
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
describe("storybook host", () => {
|
|
352
|
+
it("exports a stable host title", () => {
|
|
353
|
+
expect(storybookHostTitle).toBe("Storybook Host");
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
"""
|
|
357
|
+
ctx.write_file(src_root / "App.test.ts", content)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def _write_sb_vite_config(ctx: RunContext, sb_root: Path) -> None:
|
|
361
|
+
content = """import { defineConfig } from "vite";
|
|
362
|
+
import react from "@vitejs/plugin-react";
|
|
363
|
+
|
|
364
|
+
export default defineConfig({
|
|
365
|
+
plugins: [react()],
|
|
366
|
+
});
|
|
367
|
+
"""
|
|
368
|
+
ctx.write_file(sb_root / "vite.config.ts", content)
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def _write_sb_main(ctx: RunContext, path: Path, ui_pkg: str) -> None:
|
|
372
|
+
content = f"""import type {{ StorybookConfig }} from "@storybook/react-vite";
|
|
373
|
+
|
|
374
|
+
const config: StorybookConfig = {{
|
|
375
|
+
stories: [
|
|
376
|
+
"../../{ui_pkg}/src/**/*.stories.@(ts|tsx)",
|
|
377
|
+
],
|
|
378
|
+
addons: ["@storybook/addon-essentials"],
|
|
379
|
+
framework: {{
|
|
380
|
+
name: "@storybook/react-vite",
|
|
381
|
+
options: {{}},
|
|
382
|
+
}},
|
|
383
|
+
}};
|
|
384
|
+
|
|
385
|
+
export default config;
|
|
386
|
+
"""
|
|
387
|
+
ctx.write_file(path, content)
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def _write_sb_preview(ctx: RunContext, path: Path) -> None:
|
|
391
|
+
content = """import { CssBaseline, ThemeProvider, createTheme } from "@mui/material";
|
|
392
|
+
import type { Preview } from "@storybook/react";
|
|
393
|
+
import { Fragment, createElement } from "react";
|
|
394
|
+
|
|
395
|
+
const theme = createTheme();
|
|
396
|
+
|
|
397
|
+
const preview: Preview = {
|
|
398
|
+
decorators: [
|
|
399
|
+
(Story) =>
|
|
400
|
+
createElement(
|
|
401
|
+
ThemeProvider,
|
|
402
|
+
{ theme },
|
|
403
|
+
createElement(
|
|
404
|
+
Fragment,
|
|
405
|
+
null,
|
|
406
|
+
createElement(CssBaseline),
|
|
407
|
+
createElement(Story),
|
|
408
|
+
),
|
|
409
|
+
),
|
|
410
|
+
],
|
|
411
|
+
parameters: {
|
|
412
|
+
controls: {
|
|
413
|
+
matchers: {
|
|
414
|
+
color: /(background|color)$/i,
|
|
415
|
+
date: /Date$/i,
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
export default preview;
|
|
422
|
+
"""
|
|
423
|
+
ctx.write_file(path, content)
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def _write_example_story(ctx: RunContext, path: Path, ui_pkg: str) -> None:
|
|
427
|
+
content = f"""import type {{ Meta, StoryObj }} from "@storybook/react";
|
|
428
|
+
import {{ uiPackageName }} from "../index";
|
|
429
|
+
|
|
430
|
+
const ExampleComponent = () => <div>Hello from {{uiPackageName}}</div>;
|
|
431
|
+
|
|
432
|
+
const meta: Meta<typeof ExampleComponent> = {{
|
|
433
|
+
title: "{ui_pkg}/Example",
|
|
434
|
+
component: ExampleComponent,
|
|
435
|
+
}};
|
|
436
|
+
|
|
437
|
+
export default meta;
|
|
438
|
+
type Story = StoryObj<typeof ExampleComponent>;
|
|
439
|
+
|
|
440
|
+
export const Default: Story = {{}};
|
|
441
|
+
"""
|
|
442
|
+
ctx.write_file(path, content)
|