skeleton-framework 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- skeleton/__init__.py +0 -0
- skeleton/cli.py +151 -0
- skeleton/client.py +269 -0
- skeleton/infrastructure/__init__.py +1 -0
- skeleton/infrastructure/bootstrap/__init__.py +0 -0
- skeleton/infrastructure/bootstrap/src/__init__.py +0 -0
- skeleton/infrastructure/bootstrap/src/commands/__init__.py +0 -0
- skeleton/infrastructure/bootstrap/src/commands/client/__init__.py +0 -0
- skeleton/infrastructure/bootstrap/src/commands/client/init.py +486 -0
- skeleton/infrastructure/bootstrap/src/commands/client/install.py +113 -0
- skeleton/infrastructure/bootstrap/src/commands/dev/__init__.py +0 -0
- skeleton/infrastructure/bootstrap/src/commands/dev/build.py +80 -0
- skeleton/infrastructure/bootstrap/src/commands/dev/init.py +80 -0
- skeleton/infrastructure/bootstrap/src/commands/dev/install.py +168 -0
- skeleton/infrastructure/bootstrap/src/commands/dev/pack.py +55 -0
- skeleton/infrastructure/bootstrap/src/config.py +54 -0
- skeleton/infrastructure/bootstrap/src/copy.py +56 -0
- skeleton/infrastructure/bootstrap/src/load.py +221 -0
- skeleton/infrastructure/bootstrap/src/templates/app/backend/requirements.txt +1 -0
- skeleton/infrastructure/bootstrap/src/templates/app/backend/routes.json +10 -0
- skeleton/infrastructure/bootstrap/src/templates/app/backend/src/__init__.py +0 -0
- skeleton/infrastructure/bootstrap/src/templates/app/backend/src/main.py +35 -0
- skeleton/infrastructure/bootstrap/src/templates/app/frontend/package.json +21 -0
- skeleton/infrastructure/bootstrap/src/templates/app/frontend/skeleton-config.json +29 -0
- skeleton/infrastructure/bootstrap/src/templates/app/frontend/src/index.html +16 -0
- skeleton/infrastructure/bootstrap/src/templates/app/frontend/src/main.tsx +15 -0
- skeleton/infrastructure/bootstrap/src/templates/app/frontend/src/static/css/styles.css +28 -0
- skeleton/infrastructure/bootstrap/src/templates/app/frontend/src/static/img/skeleton.png +0 -0
- skeleton/infrastructure/bootstrap/src/templates/app/frontend/src/static/js/script.js +1 -0
- skeleton/infrastructure/bootstrap/src/templates/app/frontend/tsconfig.json +90 -0
- skeleton/infrastructure/bootstrap/src/templates/config/.gitignore +21 -0
- skeleton/infrastructure/bootstrap/src/templates/config/skeleton-dependencies.json +21 -0
- skeleton/infrastructure/bootstrap/src/templates/config/skeleton-layout.json +11 -0
- skeleton/infrastructure/bootstrap/src/templates/config/skeleton-schemas.json +20 -0
- skeleton/infrastructure/bootstrap/src/templates/config/skeleton-servers.json +16 -0
- skeleton/infrastructure/common/__init__.py +1 -0
- skeleton/infrastructure/common/config.json +8 -0
- skeleton/infrastructure/common/src/__init__.py +0 -0
- skeleton/infrastructure/common/src/config.py +37 -0
- skeleton/infrastructure/common/src/constants.py +4 -0
- skeleton/infrastructure/common/src/context.py +15 -0
- skeleton/infrastructure/common/src/env.py +12 -0
- skeleton/infrastructure/common/src/layout.py +68 -0
- skeleton/infrastructure/common/src/loader.py +8 -0
- skeleton/infrastructure/common/src/repository.py +12 -0
- skeleton/infrastructure/common/src/utils.py +26 -0
- skeleton/infrastructure/gateway/__init__.py +0 -0
- skeleton/infrastructure/gateway/settings/proxy.json +24 -0
- skeleton/infrastructure/gateway/settings/services.json +10 -0
- skeleton/infrastructure/gateway/src/__init__.py +0 -0
- skeleton/infrastructure/gateway/src/app.py +98 -0
- skeleton/infrastructure/gateway/src/client.py +68 -0
- skeleton/infrastructure/gateway/src/config.py +29 -0
- skeleton/infrastructure/gateway/src/context.py +31 -0
- skeleton/infrastructure/gateway/src/headers.py +17 -0
- skeleton/infrastructure/gateway/src/lifespan.py +17 -0
- skeleton/infrastructure/gateway/src/loader.py +113 -0
- skeleton/infrastructure/gateway/src/logging.py +37 -0
- skeleton/infrastructure/gateway/src/main.py +139 -0
- skeleton/infrastructure/gateway/src/parser.py +59 -0
- skeleton/infrastructure/gateway/src/registry.py +30 -0
- skeleton/infrastructure/gateway/src/reverseproxy.py +54 -0
- skeleton/infrastructure/gateway/src/router.py +74 -0
- skeleton/infrastructure/gateway/src/schemas.py +21 -0
- skeleton/infrastructure/gateway/src/service.py +123 -0
- skeleton/infrastructure/gateway/src/utils.py +48 -0
- skeleton/infrastructure/gateway/src/validation.py +89 -0
- skeleton/infrastructure/layout.json +12 -0
- skeleton/infrastructure/runners/__init__.py +0 -0
- skeleton/infrastructure/runners/src/__init__.py +0 -0
- skeleton/infrastructure/runners/src/actions.py +4 -0
- skeleton/infrastructure/runners/src/browser.py +18 -0
- skeleton/infrastructure/runners/src/cmd.py +7 -0
- skeleton/infrastructure/runners/src/command.py +7 -0
- skeleton/infrastructure/runners/src/frontend.py +35 -0
- skeleton/infrastructure/runners/src/gateway.py +104 -0
- skeleton/infrastructure/runners/src/hook.py +53 -0
- skeleton/infrastructure/runners/src/main.py +78 -0
- skeleton/infrastructure/runners/src/packages.py +35 -0
- skeleton/infrastructure/runners/src/parser.py +84 -0
- skeleton/infrastructure/runners/src/process.py +99 -0
- skeleton/infrastructure/runners/src/services.py +16 -0
- skeleton/infrastructure/runners/src/utils.py +6 -0
- skeleton/infrastructure/runners/src/validation.py +28 -0
- skeleton/packages/.skeleton/skeleton-cli-1.0.0.tgz +0 -0
- skeleton/packages/.skeleton/skeleton-webpack-1.0.0.tgz +0 -0
- skeleton/root.py +234 -0
- skeleton_framework-0.1.0.dist-info/METADATA +440 -0
- skeleton_framework-0.1.0.dist-info/RECORD +93 -0
- skeleton_framework-0.1.0.dist-info/WHEEL +5 -0
- skeleton_framework-0.1.0.dist-info/entry_points.txt +2 -0
- skeleton_framework-0.1.0.dist-info/licenses/LICENSE +146 -0
- skeleton_framework-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import subprocess
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
def dev_init(
|
|
7
|
+
framework_root: Path,
|
|
8
|
+
) -> None:
|
|
9
|
+
|
|
10
|
+
framework_root = framework_root.resolve()
|
|
11
|
+
|
|
12
|
+
# ---------------------------------------------------------
|
|
13
|
+
# Validate framework package configuration
|
|
14
|
+
# ---------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
pyproject = framework_root / "pyproject.toml"
|
|
17
|
+
|
|
18
|
+
if not pyproject.is_file():
|
|
19
|
+
|
|
20
|
+
raise FileNotFoundError(
|
|
21
|
+
f"Framework Python package configuration not found: "
|
|
22
|
+
f"{pyproject}"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# ---------------------------------------------------------
|
|
26
|
+
# Generate framework development requirements
|
|
27
|
+
# ---------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
requirements = framework_root / "requirements.txt"
|
|
30
|
+
|
|
31
|
+
if not requirements.is_file():
|
|
32
|
+
|
|
33
|
+
print(
|
|
34
|
+
f"INFO: Creating framework requirements file: "
|
|
35
|
+
f"{requirements}"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
requirements.write_text(
|
|
39
|
+
"build\n"
|
|
40
|
+
"twine\n",
|
|
41
|
+
encoding="utf-8",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# ---------------------------------------------------------
|
|
45
|
+
# Create framework root virtual environment
|
|
46
|
+
# ---------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
venv = framework_root / ".venv"
|
|
49
|
+
|
|
50
|
+
if not venv.is_dir():
|
|
51
|
+
|
|
52
|
+
print(
|
|
53
|
+
f"INFO: Creating framework virtual environment: "
|
|
54
|
+
f"{venv}"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
subprocess.run(
|
|
58
|
+
[
|
|
59
|
+
sys.executable,
|
|
60
|
+
"-m",
|
|
61
|
+
"venv",
|
|
62
|
+
str(venv),
|
|
63
|
+
],
|
|
64
|
+
cwd=framework_root,
|
|
65
|
+
check=True,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
python = (
|
|
69
|
+
venv / "Scripts" / "python.exe"
|
|
70
|
+
if os.name == "nt"
|
|
71
|
+
else venv / "bin" / "python"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
if not python.is_file():
|
|
75
|
+
|
|
76
|
+
raise FileNotFoundError(
|
|
77
|
+
f"Framework Python executable not found: {python}"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
print("INFO: Framework development initialization complete")
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import os, sys
|
|
2
|
+
import subprocess
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
def dev_install(
|
|
7
|
+
framework_root: Path,
|
|
8
|
+
) -> None:
|
|
9
|
+
|
|
10
|
+
framework_root = framework_root.resolve()
|
|
11
|
+
|
|
12
|
+
# ---------------------------------------------------------
|
|
13
|
+
# Install framework root development requirements
|
|
14
|
+
# ---------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
requirements = framework_root / "requirements.txt"
|
|
17
|
+
|
|
18
|
+
if not requirements.is_file():
|
|
19
|
+
|
|
20
|
+
raise FileNotFoundError(
|
|
21
|
+
f"Framework Python requirements not found: "
|
|
22
|
+
f"{requirements}"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
venv = framework_root / ".venv"
|
|
26
|
+
|
|
27
|
+
if not venv.is_dir():
|
|
28
|
+
|
|
29
|
+
raise FileNotFoundError(
|
|
30
|
+
f"Framework virtual environment not found: {venv}. "
|
|
31
|
+
"Run --dev-init first."
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
python = (
|
|
35
|
+
venv / "Scripts" / "python.exe"
|
|
36
|
+
if os.name == "nt"
|
|
37
|
+
else venv / "bin" / "python"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if not python.is_file():
|
|
41
|
+
|
|
42
|
+
raise FileNotFoundError(
|
|
43
|
+
f"Framework Python executable not found: {python}"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
print(
|
|
47
|
+
f"INFO: Installing framework Python requirements: "
|
|
48
|
+
f"{requirements}"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
subprocess.run(
|
|
52
|
+
[
|
|
53
|
+
str(python),
|
|
54
|
+
"-m",
|
|
55
|
+
"pip",
|
|
56
|
+
"install",
|
|
57
|
+
"-r",
|
|
58
|
+
str(requirements),
|
|
59
|
+
],
|
|
60
|
+
cwd=framework_root,
|
|
61
|
+
check=True,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# ---------------------------------------------------------
|
|
65
|
+
# Validate framework package configuration
|
|
66
|
+
# ---------------------------------------------------------
|
|
67
|
+
|
|
68
|
+
pyproject = framework_root / "pyproject.toml"
|
|
69
|
+
|
|
70
|
+
if not pyproject.is_file():
|
|
71
|
+
|
|
72
|
+
raise FileNotFoundError(
|
|
73
|
+
f"Framework Python package configuration not found: "
|
|
74
|
+
f"{pyproject}"
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# ---------------------------------------------------------
|
|
78
|
+
# Create framework gateway environment
|
|
79
|
+
# ---------------------------------------------------------
|
|
80
|
+
|
|
81
|
+
gateway_root = (
|
|
82
|
+
framework_root
|
|
83
|
+
/ "skeleton"
|
|
84
|
+
/ "infrastructure"
|
|
85
|
+
/ "gateway"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
venv = gateway_root / ".venv"
|
|
89
|
+
|
|
90
|
+
if not venv.is_dir():
|
|
91
|
+
|
|
92
|
+
print(f"INFO: Creating framework virtual environment: {venv}")
|
|
93
|
+
|
|
94
|
+
subprocess.run(
|
|
95
|
+
[
|
|
96
|
+
sys.executable,
|
|
97
|
+
"-m",
|
|
98
|
+
"venv",
|
|
99
|
+
str(venv),
|
|
100
|
+
],
|
|
101
|
+
cwd=framework_root,
|
|
102
|
+
check=True,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
python = (
|
|
106
|
+
venv / "Scripts" / "python.exe"
|
|
107
|
+
if os.name == "nt"
|
|
108
|
+
else venv / "bin" / "python"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
if not python.is_file():
|
|
112
|
+
|
|
113
|
+
raise FileNotFoundError(
|
|
114
|
+
f"Framework Python executable not found: {python}"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# ---------------------------------------------------------
|
|
118
|
+
# Install Skeleton and its declared Python dependencies
|
|
119
|
+
# ---------------------------------------------------------
|
|
120
|
+
|
|
121
|
+
print(
|
|
122
|
+
f"INFO: Installing Skeleton framework in editable mode: "
|
|
123
|
+
f"{framework_root}"
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
subprocess.run(
|
|
127
|
+
[
|
|
128
|
+
str(python),
|
|
129
|
+
"-m",
|
|
130
|
+
"pip",
|
|
131
|
+
"install",
|
|
132
|
+
"-e",
|
|
133
|
+
str(framework_root),
|
|
134
|
+
],
|
|
135
|
+
cwd=framework_root,
|
|
136
|
+
check=True,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# ---------------------------------------------------------
|
|
140
|
+
# Install framework Node.js development dependencies
|
|
141
|
+
# ---------------------------------------------------------
|
|
142
|
+
|
|
143
|
+
package_json = framework_root / "package.json"
|
|
144
|
+
|
|
145
|
+
if not package_json.is_file():
|
|
146
|
+
|
|
147
|
+
raise FileNotFoundError(
|
|
148
|
+
f"Framework package manifest not found: {package_json}"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
npm = (
|
|
152
|
+
"npm.cmd"
|
|
153
|
+
if os.name == "nt"
|
|
154
|
+
else "npm"
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
print(
|
|
158
|
+
f"INFO: Installing framework Node.js dependencies: "
|
|
159
|
+
f"{framework_root}"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
subprocess.run(
|
|
163
|
+
[npm, "install"],
|
|
164
|
+
cwd=framework_root,
|
|
165
|
+
check=True,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
print("INFO: Framework development installation complete")
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import os, shutil
|
|
2
|
+
import subprocess
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
def dev_pack(framework_root: Path) -> None:
|
|
7
|
+
|
|
8
|
+
framework_root = framework_root.resolve()
|
|
9
|
+
|
|
10
|
+
packages_root = framework_root / "skeleton" / "packages"
|
|
11
|
+
artifacts_root = packages_root / ".skeleton"
|
|
12
|
+
|
|
13
|
+
npm = "npm.cmd" if os.name == "nt" else "npm"
|
|
14
|
+
|
|
15
|
+
# 1. Build both packages from the framework root.
|
|
16
|
+
subprocess.run(
|
|
17
|
+
[npm, "run", "packages:build"],
|
|
18
|
+
cwd=framework_root,
|
|
19
|
+
check=True,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# 2. Recreate the predictable output directory.
|
|
23
|
+
if artifacts_root.exists():
|
|
24
|
+
|
|
25
|
+
shutil.rmtree(artifacts_root)
|
|
26
|
+
|
|
27
|
+
artifacts_root.mkdir(parents=True)
|
|
28
|
+
|
|
29
|
+
# 3. Pack webpack first, then the CLI.
|
|
30
|
+
for name in ("webpack", "cli"):
|
|
31
|
+
|
|
32
|
+
package_root = packages_root / name
|
|
33
|
+
|
|
34
|
+
if not (package_root / "package.json").is_file():
|
|
35
|
+
|
|
36
|
+
raise FileNotFoundError(
|
|
37
|
+
f"Package manifest not found: "
|
|
38
|
+
f"{package_root / 'package.json'}"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
subprocess.run(
|
|
42
|
+
[
|
|
43
|
+
npm,
|
|
44
|
+
"pack",
|
|
45
|
+
"--pack-destination",
|
|
46
|
+
str(artifacts_root),
|
|
47
|
+
],
|
|
48
|
+
cwd=package_root,
|
|
49
|
+
check=True,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
print(
|
|
53
|
+
f"\nSkeleton packages created in:\n"
|
|
54
|
+
f"{artifacts_root}"
|
|
55
|
+
)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
def config(
|
|
6
|
+
framework_root: Path,
|
|
7
|
+
project_root: Path,
|
|
8
|
+
) -> None:
|
|
9
|
+
|
|
10
|
+
templates = (
|
|
11
|
+
framework_root
|
|
12
|
+
/ "skeleton"
|
|
13
|
+
/ "infrastructure"
|
|
14
|
+
/ "bootstrap"
|
|
15
|
+
/ "src"
|
|
16
|
+
/ "templates"
|
|
17
|
+
/ "config"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
if not templates.is_dir():
|
|
21
|
+
|
|
22
|
+
raise FileNotFoundError(
|
|
23
|
+
f"Configuration templates not found: {templates}"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
project_root = project_root.resolve()
|
|
27
|
+
|
|
28
|
+
project_root.mkdir(
|
|
29
|
+
parents=True,
|
|
30
|
+
exist_ok=True,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
for template in templates.iterdir():
|
|
34
|
+
|
|
35
|
+
destination = project_root / template.name
|
|
36
|
+
|
|
37
|
+
if destination.exists():
|
|
38
|
+
|
|
39
|
+
print(
|
|
40
|
+
f"INFO: Preserving existing file: {destination}"
|
|
41
|
+
)
|
|
42
|
+
continue
|
|
43
|
+
|
|
44
|
+
if template.is_dir():
|
|
45
|
+
|
|
46
|
+
shutil.copytree(template, destination)
|
|
47
|
+
|
|
48
|
+
else:
|
|
49
|
+
|
|
50
|
+
shutil.copy2(template, destination)
|
|
51
|
+
|
|
52
|
+
print(f"INFO: Created: {destination}")
|
|
53
|
+
|
|
54
|
+
print("INFO: Configuration complete")
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
def copy_template(source: Path, target: Path) -> None:
|
|
6
|
+
|
|
7
|
+
target.mkdir(parents=True, exist_ok=True)
|
|
8
|
+
|
|
9
|
+
for item in source.iterdir():
|
|
10
|
+
|
|
11
|
+
destination = target / item.name
|
|
12
|
+
|
|
13
|
+
if destination.exists():
|
|
14
|
+
|
|
15
|
+
if item.is_dir() and destination.is_dir():
|
|
16
|
+
copy_template(item, destination)
|
|
17
|
+
|
|
18
|
+
continue
|
|
19
|
+
|
|
20
|
+
if item.is_dir():
|
|
21
|
+
shutil.copytree(item, destination)
|
|
22
|
+
|
|
23
|
+
else:
|
|
24
|
+
shutil.copy2(item, destination)
|
|
25
|
+
|
|
26
|
+
def copy_app_template(
|
|
27
|
+
source: Path,
|
|
28
|
+
target: Path,
|
|
29
|
+
frontend: str,
|
|
30
|
+
backend: str,
|
|
31
|
+
) -> None:
|
|
32
|
+
|
|
33
|
+
target.mkdir(parents=True, exist_ok=True)
|
|
34
|
+
|
|
35
|
+
directories = {
|
|
36
|
+
"frontend": frontend,
|
|
37
|
+
"backend": backend,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
for item in source.iterdir():
|
|
41
|
+
|
|
42
|
+
name = directories.get(item.name, item.name)
|
|
43
|
+
destination = target / name
|
|
44
|
+
|
|
45
|
+
if destination.exists():
|
|
46
|
+
|
|
47
|
+
if item.is_dir() and destination.is_dir():
|
|
48
|
+
copy_template(item, destination)
|
|
49
|
+
|
|
50
|
+
continue
|
|
51
|
+
|
|
52
|
+
if item.is_dir():
|
|
53
|
+
shutil.copytree(item, destination)
|
|
54
|
+
|
|
55
|
+
else:
|
|
56
|
+
shutil.copy2(item, destination)
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
def load_layout(path: Path) -> dict[str, str]:
|
|
6
|
+
|
|
7
|
+
if not path.is_file():
|
|
8
|
+
|
|
9
|
+
raise FileNotFoundError(
|
|
10
|
+
f"Project layout configuration not found: {path}"
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
with path.open("r", encoding="utf-8") as file:
|
|
14
|
+
|
|
15
|
+
config = json.load(file)
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
|
|
19
|
+
app = config["project"]["app"]
|
|
20
|
+
frontend = config["frontend"]["directory"]
|
|
21
|
+
backend = config["backend"]["directory"]
|
|
22
|
+
|
|
23
|
+
except (KeyError, TypeError) as error:
|
|
24
|
+
raise ValueError(
|
|
25
|
+
f"Invalid project layout configuration: {path}"
|
|
26
|
+
) from error
|
|
27
|
+
|
|
28
|
+
values = {
|
|
29
|
+
"project.app": app,
|
|
30
|
+
"frontend.directory": frontend,
|
|
31
|
+
"backend.directory": backend,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for key, value in values.items():
|
|
35
|
+
|
|
36
|
+
if (
|
|
37
|
+
not isinstance(value, str)
|
|
38
|
+
or not value.strip()
|
|
39
|
+
or Path(value).is_absolute()
|
|
40
|
+
or len(Path(value).parts) != 1
|
|
41
|
+
or value in (".", "..")
|
|
42
|
+
):
|
|
43
|
+
raise ValueError(
|
|
44
|
+
f"Invalid directory name for '{key}': {value!r}"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
"app": app,
|
|
49
|
+
"frontend": frontend,
|
|
50
|
+
"backend": backend,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# def load_dependencies(path: Path) -> dict:
|
|
54
|
+
|
|
55
|
+
# if not path.is_file():
|
|
56
|
+
# raise FileNotFoundError(
|
|
57
|
+
# f"Dependencies configuration not found: {path}"
|
|
58
|
+
# )
|
|
59
|
+
|
|
60
|
+
# with path.open(
|
|
61
|
+
# "r",
|
|
62
|
+
# encoding="utf-8",
|
|
63
|
+
# ) as file:
|
|
64
|
+
# config = json.load(file)
|
|
65
|
+
|
|
66
|
+
# if not isinstance(config, dict):
|
|
67
|
+
# raise ValueError(
|
|
68
|
+
# f"Invalid dependencies configuration: {path}"
|
|
69
|
+
# )
|
|
70
|
+
|
|
71
|
+
# frontend = config.get("frontend")
|
|
72
|
+
# backend = config.get("backend")
|
|
73
|
+
|
|
74
|
+
# if not isinstance(frontend, dict):
|
|
75
|
+
# raise ValueError(
|
|
76
|
+
# f"Invalid frontend configuration: {path}"
|
|
77
|
+
# )
|
|
78
|
+
|
|
79
|
+
# packages = frontend.get("packages")
|
|
80
|
+
|
|
81
|
+
# if not isinstance(packages, dict):
|
|
82
|
+
# raise ValueError(
|
|
83
|
+
# f"Invalid frontend package configuration: {path}"
|
|
84
|
+
# )
|
|
85
|
+
|
|
86
|
+
# for group in ("dependencies", "devDependencies"):
|
|
87
|
+
|
|
88
|
+
# values = packages.get(group, {})
|
|
89
|
+
|
|
90
|
+
# if not isinstance(values, dict):
|
|
91
|
+
# raise ValueError(
|
|
92
|
+
# f"Invalid frontend '{group}' configuration: {path}"
|
|
93
|
+
# )
|
|
94
|
+
|
|
95
|
+
# if not all(
|
|
96
|
+
# isinstance(name, str)
|
|
97
|
+
# and isinstance(version, str)
|
|
98
|
+
# for name, version in values.items()
|
|
99
|
+
# ):
|
|
100
|
+
# raise ValueError(
|
|
101
|
+
# f"Invalid package entries in frontend '{group}': "
|
|
102
|
+
# f"{path}"
|
|
103
|
+
# )
|
|
104
|
+
|
|
105
|
+
# requirements = (
|
|
106
|
+
# backend.get("requirements")
|
|
107
|
+
# if isinstance(backend, dict)
|
|
108
|
+
# else None
|
|
109
|
+
# )
|
|
110
|
+
|
|
111
|
+
# if not isinstance(requirements, list) or not all(
|
|
112
|
+
# isinstance(requirement, str)
|
|
113
|
+
# for requirement in requirements
|
|
114
|
+
# ):
|
|
115
|
+
# raise ValueError(
|
|
116
|
+
# f"Invalid backend requirements configuration: {path}"
|
|
117
|
+
# )
|
|
118
|
+
|
|
119
|
+
# return {
|
|
120
|
+
# "frontend": packages,
|
|
121
|
+
# "backend": requirements,
|
|
122
|
+
# }
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def load_dependencies(path: Path) -> dict:
|
|
126
|
+
|
|
127
|
+
if not path.is_file():
|
|
128
|
+
raise FileNotFoundError(
|
|
129
|
+
f"Dependencies configuration not found: {path}"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
with path.open(
|
|
133
|
+
"r",
|
|
134
|
+
encoding="utf-8",
|
|
135
|
+
) as file:
|
|
136
|
+
config = json.load(file)
|
|
137
|
+
|
|
138
|
+
if not isinstance(config, dict):
|
|
139
|
+
raise ValueError(
|
|
140
|
+
f"Invalid dependencies configuration: {path}"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# ---------------------------------------------------------
|
|
144
|
+
# Validate frontend configuration
|
|
145
|
+
# ---------------------------------------------------------
|
|
146
|
+
|
|
147
|
+
frontend = config.get("frontend")
|
|
148
|
+
|
|
149
|
+
if not isinstance(frontend, dict):
|
|
150
|
+
raise ValueError(
|
|
151
|
+
f"Invalid frontend configuration: {path}"
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
packages = frontend.get("packages")
|
|
155
|
+
|
|
156
|
+
if not isinstance(packages, dict):
|
|
157
|
+
raise ValueError(
|
|
158
|
+
f"Invalid frontend package configuration: {path}"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
for group in ("dependencies", "devDependencies"):
|
|
162
|
+
|
|
163
|
+
values = packages.get(group, {})
|
|
164
|
+
|
|
165
|
+
if not isinstance(values, dict):
|
|
166
|
+
raise ValueError(
|
|
167
|
+
f"Invalid frontend '{group}' configuration: {path}"
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
if not all(
|
|
171
|
+
isinstance(name, str)
|
|
172
|
+
and name.strip()
|
|
173
|
+
and isinstance(version, str)
|
|
174
|
+
and version.strip()
|
|
175
|
+
for name, version in values.items()
|
|
176
|
+
):
|
|
177
|
+
raise ValueError(
|
|
178
|
+
f"Invalid package entries in frontend "
|
|
179
|
+
f"'{group}': {path}"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# ---------------------------------------------------------
|
|
183
|
+
# Validate backend configuration
|
|
184
|
+
# ---------------------------------------------------------
|
|
185
|
+
|
|
186
|
+
backend = config.get("backend")
|
|
187
|
+
|
|
188
|
+
if not isinstance(backend, dict):
|
|
189
|
+
raise ValueError(
|
|
190
|
+
f"Invalid backend configuration: {path}"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
requirements = backend.get("requirements")
|
|
194
|
+
|
|
195
|
+
if not isinstance(requirements, dict):
|
|
196
|
+
raise ValueError(
|
|
197
|
+
f"Invalid backend requirements configuration: "
|
|
198
|
+
f"'backend.requirements' must be an object: {path}"
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
if not all(
|
|
202
|
+
isinstance(name, str)
|
|
203
|
+
and name.strip()
|
|
204
|
+
and isinstance(specifier, str)
|
|
205
|
+
and specifier.strip()
|
|
206
|
+
for name, specifier in requirements.items()
|
|
207
|
+
):
|
|
208
|
+
raise ValueError(
|
|
209
|
+
f"Invalid backend requirements entries: {path}. "
|
|
210
|
+
"Expected package names mapped to non-empty "
|
|
211
|
+
"version specification strings."
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# ---------------------------------------------------------
|
|
215
|
+
# Return the normalized configuration
|
|
216
|
+
# ---------------------------------------------------------
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
"frontend": packages,
|
|
220
|
+
"backend": requirements,
|
|
221
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
fastapi>=0.145,<0.146
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from fastapi import FastAPI
|
|
4
|
+
# from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
app = FastAPI(
|
|
7
|
+
# name="Backend API Docs",
|
|
8
|
+
title="Backend API Docs",
|
|
9
|
+
description="Backend API Docs",
|
|
10
|
+
version="1.0.0",
|
|
11
|
+
# lifespan=lifespan,
|
|
12
|
+
swagger_ui_parameters={
|
|
13
|
+
"docExpansion": "none",
|
|
14
|
+
"displayRequestDuration": True,
|
|
15
|
+
"defaultModelsExpandDepth": -1
|
|
16
|
+
},
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# dynamically load routes.json to creat
|
|
20
|
+
# endpoints or access using json indexing
|
|
21
|
+
BASE = Path(__file__).resolve().parents[1]
|
|
22
|
+
with open(BASE/"routes.json") as endpoints:
|
|
23
|
+
ROUTES = json.load(endpoints)["routes"]
|
|
24
|
+
|
|
25
|
+
# html response example!
|
|
26
|
+
from fastapi.responses import HTMLResponse
|
|
27
|
+
@app.get(
|
|
28
|
+
ROUTES["test"]["route"],
|
|
29
|
+
summary=ROUTES["test"]["summary"],
|
|
30
|
+
tags=ROUTES["test"]["tags"],
|
|
31
|
+
response_class=HTMLResponse
|
|
32
|
+
)
|
|
33
|
+
def page():
|
|
34
|
+
html = "<h1>FastAPI!</h1>"
|
|
35
|
+
return HTMLResponse(content=html)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "skeleton-app",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "skeleton-app",
|
|
5
|
+
"author": "client-author",
|
|
6
|
+
"license": "ISC",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"typescript": "^6.0.3",
|
|
11
|
+
"@skeleton/cli": "file:../.skeleton/packages/skeleton-cli-1.0.0.tgz",
|
|
12
|
+
"@skeleton/webpack": "file:../.skeleton/packages/skeleton-webpack-1.0.0.tgz"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"serve": "skeleton serve",
|
|
16
|
+
"build": "skeleton build",
|
|
17
|
+
"preview": "skeleton preview",
|
|
18
|
+
"clean": "skeleton clean",
|
|
19
|
+
"purge": "skeleton purge"
|
|
20
|
+
}
|
|
21
|
+
}
|