create-einja-app 0.2.2 → 0.2.6

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.
@@ -0,0 +1,108 @@
1
+ /**
2
+ * 環境変数管理の共通処理
3
+ *
4
+ * scripts/env.ts と scripts/env-rotate-secrets.ts で共有される
5
+ * 共通のユーティリティ関数と型定義を提供します。
6
+ */
7
+
8
+ import fs from "node:fs";
9
+ import path from "node:path";
10
+
11
+ const cwd = process.cwd();
12
+
13
+ /** 環境変数ファイルのパス */
14
+ export const ENV_KEYS_PATH = path.join(cwd, ".env.keys");
15
+
16
+ /**
17
+ * 環境設定の定義
18
+ */
19
+ export interface EnvironmentConfig {
20
+ name: string;
21
+ file: string;
22
+ privateKeyEnv: string;
23
+ description: string;
24
+ }
25
+
26
+ /**
27
+ * サポートされる環境の定義
28
+ */
29
+ export const ENVIRONMENTS: EnvironmentConfig[] = [
30
+ {
31
+ name: "local",
32
+ file: ".env.local",
33
+ privateKeyEnv: "DOTENV_PRIVATE_KEY_LOCAL",
34
+ description: "ローカル開発環境",
35
+ },
36
+ {
37
+ name: "development",
38
+ file: ".env.development",
39
+ privateKeyEnv: "DOTENV_PRIVATE_KEY_DEVELOPMENT",
40
+ description: "開発環境",
41
+ },
42
+ {
43
+ name: "staging",
44
+ file: ".env.staging",
45
+ privateKeyEnv: "DOTENV_PRIVATE_KEY_STAGING",
46
+ description: "ステージング環境",
47
+ },
48
+ {
49
+ name: "production",
50
+ file: ".env.production",
51
+ privateKeyEnv: "DOTENV_PRIVATE_KEY_PRODUCTION",
52
+ description: "本番環境",
53
+ },
54
+ {
55
+ name: "ci",
56
+ file: ".env.ci",
57
+ privateKeyEnv: "DOTENV_PRIVATE_KEY_CI",
58
+ description: "CI環境",
59
+ },
60
+ ];
61
+
62
+ /**
63
+ * 環境変数ファイルを読み込んでパース
64
+ *
65
+ * @param filePath - パースする環境変数ファイルのパス
66
+ * @returns 環境変数のキーバリューペア
67
+ */
68
+ export function parseEnvFile(filePath: string): Record<string, string> {
69
+ if (!fs.existsSync(filePath)) {
70
+ return {};
71
+ }
72
+ const content = fs.readFileSync(filePath, "utf-8");
73
+ const result: Record<string, string> = {};
74
+
75
+ for (const line of content.split("\n")) {
76
+ const trimmed = line.trim();
77
+ if (!trimmed || trimmed.startsWith("#")) continue;
78
+
79
+ const match = trimmed.match(/^([^=]+)=(.*)$/);
80
+ if (match) {
81
+ const key = match[1].trim();
82
+ let value = match[2].trim();
83
+ // クォートを除去
84
+ if (
85
+ (value.startsWith('"') && value.endsWith('"')) ||
86
+ (value.startsWith("'") && value.endsWith("'"))
87
+ ) {
88
+ value = value.slice(1, -1);
89
+ }
90
+ result[key] = value;
91
+ }
92
+ }
93
+ return result;
94
+ }
95
+
96
+ /**
97
+ * .env.keysから指定された環境の秘密鍵を取得
98
+ *
99
+ * @param privateKeyEnv - 秘密鍵の環境変数名(例: DOTENV_PRIVATE_KEY_LOCAL)
100
+ * @returns 秘密鍵の値。見つからない場合はnull
101
+ */
102
+ export function getPrivateKey(privateKeyEnv: string): string | null {
103
+ if (!fs.existsSync(ENV_KEYS_PATH)) {
104
+ return null;
105
+ }
106
+ const keys = parseEnvFile(ENV_KEYS_PATH);
107
+ return keys[privateKeyEnv] || null;
108
+ }
@@ -12,9 +12,11 @@
12
12
  import {
13
13
  copyFileSync,
14
14
  existsSync,
15
+ lstatSync,
15
16
  mkdirSync,
16
17
  readFileSync,
17
18
  rmSync,
19
+ statSync,
18
20
  writeFileSync,
19
21
  } from "node:fs";
20
22
  import { dirname, join, relative } from "node:path";
@@ -165,12 +167,34 @@ function transformImports(content: string): string {
165
167
  return content.replace(/@repo\//g, "{{packageName}}/");
166
168
  }
167
169
 
170
+ /**
171
+ * @einja:template-exclude マーカーを除去し、除外後の空行・水平線をクリーンアップ
172
+ */
173
+ function removeExcludeMarkers(content: string): string {
174
+ const excludePattern =
175
+ /<!-- @einja:template-exclude:start -->[\s\S]*?<!-- @einja:template-exclude:end -->/g;
176
+ let result = content.replace(excludePattern, "");
177
+
178
+ // 連続する水平線を1つに
179
+ result = result.replace(/(\n---\s*){2,}/g, "\n---\n");
180
+
181
+ // 3行以上の空行を2行に圧縮
182
+ result = result.replace(/\n{3,}/g, "\n\n");
183
+
184
+ return result;
185
+ }
186
+
168
187
  /**
169
188
  * ファイル内容を変換
170
189
  */
171
190
  function transformFileContent(filePath: string, content: string): string {
172
191
  const fileName = filePath.split("/").pop() || "";
173
192
 
193
+ // ルートREADME.mdの変換(@einja:template-exclude マーカー除去)
194
+ if (filePath === "README.md") {
195
+ return removeExcludeMarkers(content);
196
+ }
197
+
174
198
  // package.json の変換
175
199
  if (fileName === "package.json") {
176
200
  return transformPackageJson(content, filePath);
@@ -201,7 +225,7 @@ async function main(): Promise<void> {
201
225
  "packages",
202
226
  "create-einja-app",
203
227
  "templates",
204
- "turborepo-pandacss"
228
+ "default"
205
229
  );
206
230
 
207
231
  console.log("\n🔄 テンプレート更新を開始...\n");
@@ -251,6 +275,22 @@ async function main(): Promise<void> {
251
275
  const sourcePath = join(rootDir, file);
252
276
  const destPath = join(templateDir, file);
253
277
 
278
+ // ファイルの存在確認
279
+ if (!existsSync(sourcePath)) {
280
+ continue;
281
+ }
282
+
283
+ // シンボリックリンクの場合はスキップ
284
+ const stats = lstatSync(sourcePath);
285
+ if (stats.isSymbolicLink()) {
286
+ continue;
287
+ }
288
+
289
+ // ディレクトリの場合はスキップ(念のため)
290
+ if (stats.isDirectory()) {
291
+ continue;
292
+ }
293
+
254
294
  // ディレクトリを作成
255
295
  const destDir = dirname(destPath);
256
296
  if (!existsSync(destDir)) {