tssetup 1.0.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.
tssetup/__init__.py ADDED
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
tssetup/__main__.py ADDED
@@ -0,0 +1,174 @@
1
+ import argparse
2
+ import os
3
+ import sys
4
+ import subprocess
5
+ import shutil
6
+ import urllib.request
7
+ from pathlib import Path
8
+ from typing import Optional
9
+ from . import __version__
10
+ from .templates import TSCONFIG, SERVER_TS, INDEX_TS, get_html
11
+
12
+ # --- Console setup (Windows: enable ANSI + force UTF-8) ---
13
+
14
+ def _setup_console():
15
+ if sys.platform == "win32":
16
+ try:
17
+ import ctypes
18
+ ctypes.windll.kernel32.SetConsoleMode(
19
+ ctypes.windll.kernel32.GetStdHandle(-11), 7)
20
+ except Exception:
21
+ pass
22
+ if hasattr(sys.stdout, "reconfigure"):
23
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
24
+ sys.stderr.reconfigure(encoding="utf-8", errors="replace")
25
+
26
+ _setup_console()
27
+
28
+ R = "\033[0m"
29
+ CYAN = "\033[36m"
30
+ GREEN = "\033[32m"
31
+ YELLOW = "\033[33m"
32
+ WHITE = "\033[97m"
33
+ GRAY = "\033[90m"
34
+
35
+ def c(text, color): return f"{color}{text}{R}"
36
+
37
+
38
+ # --- Version check ---
39
+
40
+ def fetch_remote_version() -> Optional[str]:
41
+ try:
42
+ url = "https://raw.githubusercontent.com/Lapius7/tssetup/main/version.txt"
43
+ with urllib.request.urlopen(url, timeout=3) as r:
44
+ return r.read().decode().strip()
45
+ except Exception:
46
+ return None
47
+
48
+
49
+ # --- Info screen ---
50
+
51
+ def show_info(remote: Optional[str]):
52
+ print()
53
+ print(c("🎨 tssetup", CYAN) + c(f" v{__version__}", GRAY))
54
+ print("Bun + TypeScript フロントエンド環境を1コマンドで構築するツール")
55
+ print()
56
+ print(c("開発者 : ", YELLOW) + "Lapius7")
57
+ print(c("X : ", YELLOW) + "https://x.com/Lapius7")
58
+ print(c("GitHub : ", YELLOW) + "https://github.com/Lapius7/tssetup")
59
+ print()
60
+ if remote is None:
61
+ print(f"バージョン : {__version__} " + c("(バージョン確認失敗)", GRAY))
62
+ elif remote == __version__:
63
+ print(f"バージョン : {__version__} " + c("✅ 最新です", GREEN))
64
+ else:
65
+ print(f"バージョン : {__version__} " + c(f"⬆ 最新: {remote}", YELLOW))
66
+ print()
67
+ print(c("使い方 : tssetup <プロジェクト名> [--mode <モード>]", GRAY))
68
+ print(c("ヘルプ : tssetup --help", GRAY))
69
+ print()
70
+
71
+
72
+ # --- Project creation ---
73
+
74
+ def create_project(name: str, mode: str, title: str, code: bool):
75
+ project_dir = Path(name)
76
+
77
+ print()
78
+ print(c("🔨 ", CYAN) + c(name, WHITE) + c(" を構築中...", CYAN))
79
+ print()
80
+
81
+ (project_dir / "src").mkdir(parents=True, exist_ok=True)
82
+ (project_dir / "dist").mkdir(parents=True, exist_ok=True)
83
+ print(c(" 📁 src/ dist/ フォルダを作成しました", GRAY))
84
+
85
+ os.chdir(project_dir)
86
+
87
+ subprocess.run(["bun", "init", "-y"], capture_output=True)
88
+ stale = Path("index.ts")
89
+ if stale.exists():
90
+ stale.unlink()
91
+ print(" 📦 package.json" + c(" (bun init)", GRAY))
92
+
93
+ Path("tsconfig.json").write_text(TSCONFIG, encoding="utf-8")
94
+ print(c(" ✅ tsconfig.json", GREEN))
95
+
96
+ Path("server.ts").write_text(SERVER_TS, encoding="utf-8")
97
+ print(c(" ✅ server.ts", GREEN))
98
+
99
+ Path("src/index.ts").write_text(INDEX_TS[mode], encoding="utf-8")
100
+ print(c(" ✅ src/index.ts", GREEN))
101
+
102
+ Path("index.html").write_text(get_html(mode, title), encoding="utf-8")
103
+ print(c(" ✅ index.html", GREEN))
104
+
105
+ print()
106
+ print(c(" ──────────────────────────────────────────", GRAY))
107
+ print(" ✨ " + c(name, CYAN) + c(" セットアップ完了!", GREEN))
108
+ print(c(" ──────────────────────────────────────────", GRAY))
109
+ print()
110
+ print(c(f" 📁 {name}/", YELLOW))
111
+ print(" ├── src/")
112
+ print(" │ └── index.ts")
113
+ print(" ├── dist/ " + c("← tsc が自動生成", GRAY))
114
+ print(" ├── index.html")
115
+ print(" ├── server.ts")
116
+ print(" ├── tsconfig.json")
117
+ print(" └── package.json")
118
+ print()
119
+ print(c(f" 📂 {Path.cwd()}", GRAY))
120
+ print()
121
+ print(c(" 🚀 次のステップ:", CYAN))
122
+ print(" " + c("tsbuild", WHITE) + c(" 開発サーバーを起動", GRAY))
123
+ print()
124
+
125
+ if code and shutil.which("code"):
126
+ subprocess.run(["code", "."])
127
+
128
+
129
+ # --- Entry point ---
130
+
131
+ def main():
132
+ parser = argparse.ArgumentParser(
133
+ prog="tssetup",
134
+ description="Bun + TypeScript フロントエンド環境を1コマンドで構築するツール",
135
+ add_help=False,
136
+ )
137
+ parser.add_argument("project_name", nargs="?", help="作成するプロジェクトのフォルダ名")
138
+ parser.add_argument("--mode", "-m",
139
+ choices=["default", "tailwind", "router", "empty"],
140
+ default="default",
141
+ help="テンプレートモード (default/tailwind/router/empty)")
142
+ parser.add_argument("--title", "-t", default="Bun + TS App",
143
+ help="HTMLの <title> タグに埋め込む文字列")
144
+ parser.add_argument("--code", "-c", action="store_true",
145
+ help="セットアップ完了後に VS Code で開く")
146
+ parser.add_argument("--version", "-v", action="store_true",
147
+ help="バージョンを表示")
148
+ parser.add_argument("--help", "-h", action="store_true",
149
+ help="ヘルプを表示")
150
+
151
+ args = parser.parse_args()
152
+
153
+ if args.version:
154
+ print(f"tssetup v{__version__}")
155
+ return
156
+
157
+ remote = fetch_remote_version()
158
+
159
+ if remote and remote != __version__:
160
+ print()
161
+ print(c(f"🔄 新しいバージョン ({remote}) があります。pip install --upgrade tssetup で更新できます。", YELLOW))
162
+
163
+ if args.help or not args.project_name:
164
+ if not args.project_name:
165
+ show_info(remote)
166
+ if args.help or not args.project_name:
167
+ parser.print_help()
168
+ return
169
+
170
+ create_project(args.project_name, args.mode, args.title, args.code)
171
+
172
+
173
+ if __name__ == "__main__":
174
+ main()
tssetup/templates.py ADDED
@@ -0,0 +1,180 @@
1
+ TSCONFIG = '''{
2
+ "compilerOptions": {
3
+ "rootDir": "./src",
4
+ "outDir": "./dist",
5
+ "target": "es2020",
6
+ "module": "es2020",
7
+ "moduleResolution": "node",
8
+ "lib": ["es2020", "dom"],
9
+ "strict": true,
10
+ "skipLibCheck": true,
11
+ "isolatedModules": true
12
+ },
13
+ "include": ["src"]
14
+ }'''
15
+
16
+ SERVER_TS = '''import { watch, mkdirSync, existsSync } from "fs";
17
+ const DEFAULT_PORT = 53000;
18
+
19
+ async function findAvailablePort(startPort: number): Promise<number> {
20
+ let port = startPort;
21
+ while (port <= 65535) {
22
+ try {
23
+ const server = Bun.serve({ port, fetch() { return new Response(); } });
24
+ server.stop();
25
+ return port;
26
+ } catch { port++; }
27
+ }
28
+ return startPort;
29
+ }
30
+
31
+ const PORT = await findAvailablePort(DEFAULT_PORT);
32
+ const sockets = new Set<any>();
33
+
34
+ const notifyReload = () => {
35
+ console.log("\\u{1F504} File changed! Reloading browser...");
36
+ for (const socket of sockets) { socket.send("reload"); }
37
+ };
38
+
39
+ if (!existsSync("./dist")) mkdirSync("./dist", { recursive: true });
40
+ watch("./dist", { recursive: true }, notifyReload);
41
+ watch("./index.html", notifyReload);
42
+
43
+ Bun.serve({
44
+ port: PORT,
45
+ fetch(req: Request, server: any) {
46
+ const url = new URL(req.url);
47
+ if (url.pathname === "/ws") {
48
+ if (server.upgrade(req)) return;
49
+ return new Response("Upgrade failed", { status: 400 });
50
+ }
51
+ let filePath = "." + url.pathname;
52
+ if (filePath === "./") filePath = "./index.html";
53
+ try {
54
+ return new Response(Bun.file(filePath));
55
+ } catch {
56
+ try { return new Response(Bun.file("./index.html")); }
57
+ catch { return new Response("404 Not Found", { status: 404 }); }
58
+ }
59
+ },
60
+ websocket: {
61
+ open(ws: any) { sockets.add(ws); },
62
+ close(ws: any) { sockets.delete(ws); }
63
+ }
64
+ });
65
+ console.log(`\\u{1F30D} Bun Live Server running at http://localhost:${PORT}`);
66
+ '''
67
+
68
+ INDEX_TS = {
69
+ "default": '''const app = document.getElementById('app');
70
+ if (app) {
71
+ app.innerHTML = `
72
+ <h1>✨ Bun + TypeScript Environment</h1>
73
+ <p>Ready to develop! Edit <code>src/index.ts</code> to get started.</p>
74
+ `;
75
+ }''',
76
+
77
+ "tailwind": '''const app = document.getElementById('app');
78
+ if (app) {
79
+ app.innerHTML = `
80
+ <div class='max-w-md p-8 bg-slate-800 rounded-2xl border border-slate-700 shadow-xl text-center'>
81
+ <h1 class='text-3xl font-black mb-3 bg-gradient-to-r from-sky-400 to-blue-500 bg-clip-text text-transparent'>Tailwind Ready</h1>
82
+ <p class='text-slate-400'>Edit <code class='bg-slate-950 text-rose-400 px-1.5 py-0.5 rounded text-sm font-mono'>src/index.ts</code> to start building your UI.</p>
83
+ </div>
84
+ `;
85
+ }''',
86
+
87
+ "router": '''// ⚡ 自作SPAルーターの基本実装
88
+ const routes: Record<string, string> = {
89
+ '/': '<div class="text-center"><h1 class="text-3xl font-bold text-sky-400 mb-2">Home Page</h1><p class="text-slate-400">Welcome to the lightweight SPA initial template!</p></div>',
90
+ '/about': '<div class="text-center"><h1 class="text-3xl font-bold text-indigo-400 mb-2">About Page</h1><p class="text-slate-400">This router operates using pure HTML5 History API.</p></div>',
91
+ '/setting': '<div class="text-center"><h1 class="text-3xl font-bold text-emerald-400 mb-2">Setting Page</h1><p class="text-slate-400">Configure your system parameters here.</p></div>'
92
+ };
93
+
94
+ const render = (path: string) => {
95
+ const app = document.getElementById('app');
96
+ if (app) app.innerHTML = routes[path] || '<h1 class="text-2xl font-bold text-rose-500">404 Not Found</h1>';
97
+ document.querySelectorAll('.nav-link').forEach(link => {
98
+ const href = link.getAttribute('href');
99
+ link.classList.toggle('text-sky-400', href === path);
100
+ link.classList.toggle('text-slate-400', href !== path);
101
+ });
102
+ };
103
+
104
+ const navigate = (path: string) => { window.history.pushState({}, '', path); render(path); };
105
+
106
+ window.addEventListener('popstate', () => render(window.location.pathname));
107
+ document.addEventListener('click', (e) => {
108
+ const target = e.target as HTMLElement;
109
+ if (target.matches('.nav-link')) {
110
+ e.preventDefault();
111
+ const href = target.getAttribute('href');
112
+ if (href) navigate(href);
113
+ }
114
+ });
115
+
116
+ render(window.location.pathname);''',
117
+
118
+ "empty": "console.log('Hello TypeScript!');",
119
+ }
120
+
121
+ DESTYLE_CDN = '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/destyle.css@3.0.2/destyle.min.css">'
122
+ TAILWIND_CDN = '<script src="https://cdn.tailwindcss.com"></script>'
123
+
124
+ DEFAULT_STYLES = """ <style>
125
+ body { font-family: 'Helvetica Neue', Arial, sans-serif; background-color: #0f172a; color: #f8fafc; display: grid; place-items: center; min-height: 100vh; margin: 0; }
126
+ #app { text-align: center; }
127
+ h1 { font-size: 2.5rem; font-weight: bold; margin-bottom: 1rem; background: linear-gradient(to right, #38bdf8, #818cf8); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
128
+ p { color: #94a3b8; font-size: 1.1rem; }
129
+ code { background-color: #1e293b; padding: 0.2rem 0.4rem; border-radius: 0.25rem; color: #f43f5e; font-family: monospace; }
130
+ </style>"""
131
+
132
+ HOTRELOAD_SCRIPT = """ <script>
133
+ const ws = new WebSocket('ws://' + location.host + '/ws');
134
+ ws.onmessage = (e) => { if(e.data === 'reload') location.reload(); };
135
+ </script>"""
136
+
137
+
138
+ def get_html(mode: str, title: str) -> str:
139
+ if mode == "tailwind":
140
+ cdn = TAILWIND_CDN
141
+ styles = ""
142
+ body_class = ' class="bg-slate-900 text-slate-100 min-h-screen grid place-items-center font-sans"'
143
+ body_content = ' <div id="app"></div>'
144
+ elif mode == "router":
145
+ cdn = TAILWIND_CDN
146
+ styles = ""
147
+ body_class = ' class="bg-slate-900 text-slate-100 min-h-screen font-sans flex flex-col"'
148
+ body_content = """ <nav class="bg-slate-950 border-b border-slate-800 px-6 py-4 flex gap-6">
149
+ <a href="/" class="nav-link text-sky-400 font-bold hover:text-sky-300">\U0001f3e0 Home</a>
150
+ <a href="/about" class="nav-link text-slate-400 font-bold hover:text-slate-200">\U0001f4c4 About</a>
151
+ <a href="/setting" class="nav-link text-slate-400 font-bold hover:text-slate-200">⚙️ Setting</a>
152
+ </nav>
153
+ <main id="app" class="flex-1 grid place-items-center p-6"></main>"""
154
+ elif mode == "empty":
155
+ cdn = ""
156
+ styles = ""
157
+ body_class = ""
158
+ body_content = ' <div id="app"></div>'
159
+ else: # default
160
+ cdn = DESTYLE_CDN
161
+ styles = DEFAULT_STYLES
162
+ body_class = ""
163
+ body_content = ' <div id="app"></div>'
164
+
165
+ cdn_line = f"\n {cdn}" if cdn else ""
166
+ styles_line = f"\n{styles}" if styles else ""
167
+
168
+ return f"""<!DOCTYPE html>
169
+ <html lang="ja">
170
+ <head>
171
+ <meta charset="UTF-8">
172
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
173
+ <title>{title}</title>{cdn_line}{styles_line}
174
+ </head>
175
+ <body{body_class}>
176
+ {body_content}
177
+ <script type="module" src="./dist/index.js"></script>
178
+ {HOTRELOAD_SCRIPT}
179
+ </body>
180
+ </html>"""
@@ -0,0 +1,143 @@
1
+ Metadata-Version: 2.4
2
+ Name: tssetup
3
+ Version: 1.0.0
4
+ Summary: Bun + TypeScript フロントエンド環境を1コマンドで構築するツール
5
+ Project-URL: Homepage, https://github.com/Lapius7/tssetup
6
+ Project-URL: Issues, https://github.com/Lapius7/tssetup/issues
7
+ Author-email: Lapius7 <me@lapius7.com>
8
+ License: MIT
9
+ Keywords: bun,cli,frontend,hot-reload,scaffold,typescript
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: Microsoft :: Windows
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Software Development :: Build Tools
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+
19
+ # tssetup
20
+
21
+ PowerShellやCMDから1コマンドで、Bun + TypeScript の高速なフロントエンド開発環境(ホットリロードサーバー内蔵)を初期構築するツールです。
22
+
23
+ ## 🚀 特徴
24
+
25
+ - **瞬時にプロジェクト開始:** フォルダ作成、`bun init`、`tsconfig.json` の設定、ホットリロードサーバースクリプトの作成を自動で一括実行します。
26
+ - **多彩な初期テンプレート:**
27
+ - `default`: Destyle.css を内包したシンプルな構成(ダークモード対応)。
28
+ - `tailwind`: CDN版 Tailwind CSS が即座に使えるレイアウト構成。
29
+ - `router`: ライブラリを使わずに HTML5 History API を利用した、自作の超軽量 SPA ルーティング構成。
30
+ - `empty`: 最少構成(空の TypeScript ファイルとシンプルな HTML)。
31
+ - **エディタ連携:** `--code` オプションを付けるだけで、作成したプロジェクトフォルダを VS Code で即座に開きます。
32
+ - **自動バージョン確認:** 実行時に最新バージョンを確認し、更新がある場合は通知します。
33
+
34
+ ---
35
+
36
+ ## 🛠️ インストール方法
37
+
38
+ **pip(推奨):**
39
+
40
+ ```bash
41
+ pip install tssetup
42
+ ```
43
+
44
+ > [!NOTE]
45
+ >
46
+ > - PowerShell・CMD・Windows Terminal どれからでも使えます。
47
+ > - 動作には **Python 3.9+** と **Bun** が必要です。
48
+
49
+ ---
50
+
51
+ ## ⚙️ 動作に必要な環境(依存関係)
52
+
53
+ | ツール | 用途 | インストール |
54
+ | :--- | :--- | :--- |
55
+ | **Python 3.9+** | tssetup 本体の実行 | [python.org](https://www.python.org/) |
56
+ | **Bun** | プロジェクト初期化・TSコンパイル | `powershell -c "irm bun.sh/install.ps1 \| iex"` |
57
+ | **VS Code** (任意) | `--code` オプション使用時 | [code.visualstudio.com](https://code.visualstudio.com/) |
58
+
59
+ ---
60
+
61
+ ## ⚡ 使い方と全パラメータ一覧
62
+
63
+ ```bash
64
+ tssetup <プロジェクト名> [--mode <モード名>] [--title <タイトル名>] [--code]
65
+ ```
66
+
67
+ 引数なしで実行するとバージョン情報・開発者情報のインフォ画面が表示されます。
68
+
69
+ ### パラメータ(引数)詳細
70
+
71
+ | パラメータ | 短縮形 | 型 | 必須 | デフォルト値 | 説明 |
72
+ | :--- | :--- | :--- | :--- | :--- | :--- |
73
+ | `project_name` | - | string | **はい** | - | 作成するプロジェクトのフォルダ名 |
74
+ | `--mode` | `-m` | string | いいえ | `default` | テンプレートモード(`default` / `tailwind` / `router` / `empty`) |
75
+ | `--title` | `-t` | string | いいえ | `"Bun + TS App"` | `<title>` タグに埋め込むテキスト |
76
+ | `--code` | `-c` | flag | いいえ | - | セットアップ完了後に VS Code で開く |
77
+ | `--version` | `-v` | flag | いいえ | - | バージョンを表示 |
78
+ | `--help` | `-h` | flag | いいえ | - | ヘルプを表示 |
79
+
80
+ ---
81
+
82
+ ### コマンド実行例
83
+
84
+ ```bash
85
+ # 標準テンプレートで作成
86
+ tssetup my-app
87
+
88
+ # Tailwind CSS 組み込み + VS Code で開く
89
+ tssetup my-app --mode tailwind --code
90
+
91
+ # 自作 SPA ルーター構成
92
+ tssetup my-app --mode router --title "マイSPAサイト"
93
+
94
+ # 最小構成
95
+ tssetup my-app --mode empty
96
+ ```
97
+
98
+ ---
99
+
100
+ ## 📁 作成されるファイル構成
101
+
102
+ ```
103
+ my-app/
104
+ ├── src/
105
+ │ └── index.ts ← エントリポイント(--mode で内容が変わる)
106
+ ├── dist/ ← tsc が自動生成するJS出力先
107
+ ├── node_modules/ ← bun install が自動生成
108
+ ├── index.html ← フロントエンドのHTML
109
+ ├── server.ts ← ホットリロード対応の開発用Webサーバー
110
+ ├── tsconfig.json ← TypeScript コンパイラ設定
111
+ └── package.json ← Bun プロジェクト設定
112
+ ```
113
+
114
+ プロジェクト作成後は自動的にそのディレクトリへ移動します。そのまま `tsbuild` を実行すれば開発を始められます。
115
+
116
+ ---
117
+
118
+ ## 🔄 アップデート
119
+
120
+ ```bash
121
+ pip install --upgrade tssetup
122
+ ```
123
+
124
+ ---
125
+
126
+ ## ✉️ 問い合わせ先
127
+
128
+ - **X (旧Twitter):** [@Lapius7](https://x.com/Lapius7)
129
+ - **GitHub Issues:** [Lapius7/tssetup/issues](https://github.com/Lapius7/tssetup/issues)
130
+
131
+ ---
132
+
133
+ ## ⚠️ 免責事項
134
+
135
+ 本ソフトウェアの使用によって生じた直接的・間接的な損害について、作者は一切の責任を負いません。自己責任のもとでご使用ください。
136
+
137
+ ---
138
+
139
+ ## 📄 ライセンス & コピーライト
140
+
141
+ 本プロジェクトは [MIT License](https://opensource.org/licenses/MIT) のもとで公開されています。
142
+
143
+ Copyright (c) 2026 Lapius7
@@ -0,0 +1,7 @@
1
+ tssetup/__init__.py,sha256=J-j-u0itpEFT6irdmWmixQqYMadNl1X91TxUmoiLHMI,22
2
+ tssetup/__main__.py,sha256=4eX6_tcfwtb4RXf-QbVH7ZMnMaLUnIJCbF4R286hDWY,6062
3
+ tssetup/templates.py,sha256=oAvh1uqg0HINtqbOeE4fTjxq_12xoj5JlhTvGDtHKdw,6818
4
+ tssetup-1.0.0.dist-info/METADATA,sha256=fInzBm42W0IzNimyt5MYoyB9pBrXPOIzcoz2iFa5DMI,5299
5
+ tssetup-1.0.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
6
+ tssetup-1.0.0.dist-info/entry_points.txt,sha256=W8K8DkdCWUOp9XYLHwil7BnvaBAqtmaRMQ4CDkfeZwc,50
7
+ tssetup-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ tssetup = tssetup.__main__:main