noshift.js 0.2.0 → 0.3.0

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.
package/README-ja.md CHANGED
@@ -54,7 +54,7 @@ nsc --init
54
54
  {
55
55
  "compilerOptions": {
56
56
  "rootDir": "src",
57
- "outDir": "build"
57
+ "outDir": "dist"
58
58
  }
59
59
  }
60
60
  ```
@@ -62,7 +62,7 @@ nsc --init
62
62
  | オプション | デフォルト | 説明 |
63
63
  |---|---|---|
64
64
  | `compilerOptions.rootDir` | `"src"` | ソースディレクトリ |
65
- | `compilerOptions.outDir` | `"build"` | 出力ディレクトリ |
65
+ | `compilerOptions.outDir` | `"dist"` | 出力ディレクトリ |
66
66
 
67
67
  ---
68
68
 
package/README.md CHANGED
@@ -54,7 +54,7 @@ Generated automatically by `nsc --init` or `nsc create`.
54
54
  {
55
55
  "compilerOptions": {
56
56
  "rootDir": "src",
57
- "outDir": "build"
57
+ "outDir": "dist"
58
58
  }
59
59
  }
60
60
  ```
@@ -62,7 +62,7 @@ Generated automatically by `nsc --init` or `nsc create`.
62
62
  | Option | Default | Description |
63
63
  |---|---|---|
64
64
  | `compilerOptions.rootDir` | `"src"` | Source directory |
65
- | `compilerOptions.outDir` | `"build"` | Output directory |
65
+ | `compilerOptions.outDir` | `"dist"` | Output directory |
66
66
 
67
67
  ---
68
68
 
package/bin/cli.js CHANGED
@@ -16,7 +16,7 @@ const program = new Command();
16
16
  program
17
17
  .name("nsc")
18
18
  .description("NoShift.js compiler")
19
- .version(pkg.version)
19
+ .version(pkg.version, '-v, --version', 'output the version number')
20
20
  .option("-w, --watch", "Watch for file changes and recompile")
21
21
  .option("--init", "Create a nsjsconfig.json in the current directory")
22
22
  .option("--clean", "Delete the output directory (outDir)")
package/commands/clean.js CHANGED
@@ -1,15 +1,19 @@
1
1
  import { rm, access } from "fs/promises";
2
2
  import path from "path";
3
3
  import { loadConfig } from "../src/config.js";
4
+ import { handleSigint } from "../src/signal-handler.js";
5
+ import * as logger from "../src/logger.js";
4
6
 
5
7
  export default async function clean() {
8
+ handleSigint();
9
+
6
10
  const cwd = process.cwd();
7
11
 
8
12
  let config;
9
13
  try {
10
14
  config = await loadConfig(cwd);
11
15
  } catch (e) {
12
- console.error(`error NS0: ${e.message}`);
16
+ logger.errorCode("NS0", e.message);
13
17
  process.exit(1);
14
18
  }
15
19
 
@@ -18,12 +22,12 @@ export default async function clean() {
18
22
  try {
19
23
  await access(outDir);
20
24
  } catch {
21
- console.log(
22
- `Nothing to clean ('${config.compilerOptions.outDir}' does not exist).`,
25
+ logger.info(
26
+ `Nothing to clean (${logger.highlight(config.compilerOptions.outDir)} does not exist).`,
23
27
  );
24
28
  return;
25
29
  }
26
30
 
27
31
  await rm(outDir, { recursive: true, force: true });
28
- console.log(`Deleted '${config.compilerOptions.outDir}'.`);
32
+ logger.success(`Deleted ${logger.highlight(config.compilerOptions.outDir)}`);
29
33
  }
@@ -2,6 +2,8 @@ import { promises as fs } from "fs";
2
2
  import path from "path";
3
3
  import convert from "../src/convert.js";
4
4
  import { loadConfig } from "../src/config.js";
5
+ import { handleSigint } from "../src/signal-handler.js";
6
+ import * as logger from "../src/logger.js";
5
7
 
6
8
  async function findNsjsFiles(dir) {
7
9
  let entries;
@@ -25,13 +27,15 @@ async function findNsjsFiles(dir) {
25
27
  }
26
28
 
27
29
  export default async function compile() {
30
+ handleSigint();
31
+
28
32
  const cwd = process.cwd();
29
33
 
30
34
  let config;
31
35
  try {
32
36
  config = await loadConfig(cwd);
33
37
  } catch (e) {
34
- console.error(`error TS0: ${e.message}`);
38
+ logger.errorCode("NS0", e.message);
35
39
  process.exit(1);
36
40
  }
37
41
 
@@ -41,14 +45,15 @@ export default async function compile() {
41
45
  const files = await findNsjsFiles(rootDir);
42
46
 
43
47
  if (files === null) {
44
- console.error(
45
- `error NS0: rootDir '${config.compilerOptions.rootDir}' not found.`,
48
+ logger.errorCode(
49
+ "NS0",
50
+ `rootDir '${config.compilerOptions.rootDir}' not found.`,
46
51
  );
47
52
  process.exit(1);
48
53
  }
49
54
 
50
55
  if (files.length === 0) {
51
- console.log("No .nsjs files found.");
56
+ logger.info("No .nsjs files found.");
52
57
  return;
53
58
  }
54
59
 
@@ -68,22 +73,24 @@ export default async function compile() {
68
73
  await fs.mkdir(path.dirname(destPath), { recursive: true });
69
74
  await fs.writeFile(destPath, js, "utf-8");
70
75
 
71
- console.log(
76
+ logger.dim(
72
77
  ` ${relative.replace(/\\/g, "/")} → ${path.relative(cwd, destPath).replace(/\\/g, "/")}`,
73
78
  );
74
79
  compiled++;
75
80
  } catch (e) {
76
- console.error(
77
- ` error NS1: ${relative.replace(/\\/g, "/")}: ${e.message}`,
81
+ logger.errorCode(
82
+ "NS1",
83
+ `${relative.replace(/\\/g, "/")}: ${e.message}`,
78
84
  );
79
85
  errors++;
80
86
  }
81
87
  }
82
88
 
89
+ console.log("");
83
90
  if (errors > 0) {
84
- console.error(`\nFound ${errors} error(s). Compiled ${compiled} file(s).`);
91
+ logger.error(`Found ${errors} error(s). Compiled ${compiled} file(s).`);
85
92
  process.exit(1);
86
93
  } else {
87
- console.log(`\nSuccessfully compiled ${compiled} file(s).`);
94
+ logger.success(`Compiled ${compiled} file(s).`);
88
95
  }
89
96
  }
@@ -2,154 +2,101 @@ import { execSync } from "child_process";
2
2
  import fs from "fs/promises";
3
3
  import path from "path";
4
4
  import inquirer from "inquirer";
5
+ import { handleSigint, isUserCancelled } from "../src/signal-handler.js";
6
+ import * as logger from "../src/logger.js";
5
7
 
6
8
  export default async function create(projectNameArg) {
9
+ handleSigint();
10
+
7
11
  const cwd = process.cwd();
8
12
 
9
- // 言語選択
10
- const { lang } = await inquirer.prompt([
11
- {
12
- type: "list",
13
- name: "lang",
14
- message: "Select language / 言語を選んでください",
15
- choices: [
16
- { name: "English", value: "en" },
17
- { name: "日本語", value: "ja" },
18
- ],
19
- },
20
- ]);
21
-
22
- const t = (key) =>
23
- ({
24
- projectName: { en: "Project name:", ja: "プロジェクト名:" },
25
- creatingDir: {
26
- en: "Creating project directory:",
27
- ja: "プロジェクトディレクトリを作成:",
28
- },
29
- initializingNpm: { en: "Initializing npm...", ja: "npm を初期化中..." },
30
- creatingConfig: {
31
- en: "Created nsjsconfig.json",
32
- ja: "nsjsconfig.json を作成しました",
33
- },
34
- usePrettier: {
35
- en: "Format compiled output with Prettier?",
36
- ja: "コンパイル後のコードを Prettier で整形しますか?",
37
- },
38
- installingPrettier: {
39
- en: "Installing Prettier...",
40
- ja: "Prettier をインストール中...",
41
- },
42
- installingNoshift: {
43
- en: "Installing noshift.js...",
44
- ja: "noshift.js をインストール中...",
45
- },
46
- success: {
47
- en: "Project created successfully!",
48
- ja: "プロジェクトの作成が完了しました!",
49
- },
50
- nextSteps: {
51
- en: "Next: cd {name} && nsc compile",
52
- ja: "次のステップ: cd {name} && nsc compile",
13
+ try {
14
+ // Project name
15
+ let projectName = projectNameArg;
16
+ if (!projectName) {
17
+ const answer = await inquirer.prompt([
18
+ {
19
+ type: "input",
20
+ name: "projectName",
21
+ message: "Project name:",
22
+ default: "my-noshift-app",
23
+ },
24
+ ]);
25
+ projectName = answer.projectName;
26
+ }
27
+
28
+ const projectPath = path.join(cwd, projectName);
29
+
30
+ // Create project directory
31
+ logger.step("Creating project directory...");
32
+ await fs.mkdir(projectPath, { recursive: true });
33
+ logger.dim(` ${projectPath}`);
34
+
35
+ process.chdir(projectPath);
36
+
37
+ // npm init
38
+ logger.step("Initializing npm...");
39
+ execSync("npm init -y", { stdio: "ignore" });
40
+
41
+ // Add scripts to package.json
42
+ const pkgPath = path.join(projectPath, "package.json");
43
+ const pkg = JSON.parse(await fs.readFile(pkgPath, "utf-8"));
44
+ pkg.scripts = pkg.scripts ?? {};
45
+ pkg.scripts.compile = "nsc compile";
46
+ pkg.scripts.dev = "nsc dev";
47
+ await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
48
+
49
+ // Create nsjsconfig.json
50
+ const nsjsconfig = {
51
+ compilerOptions: {
52
+ rootDir: "src",
53
+ outDir: "dist",
53
54
  },
54
- })[key][lang];
55
+ };
56
+ await fs.writeFile(
57
+ "nsjsconfig.json",
58
+ JSON.stringify(nsjsconfig, null, 2) + "\n",
59
+ );
60
+ logger.success("Created nsjsconfig.json");
55
61
 
56
- // プロジェクト名
57
- let projectName = projectNameArg;
58
- if (!projectName) {
59
- const answer = await inquirer.prompt([
62
+ // Prettier
63
+ const { usePrettier } = await inquirer.prompt([
60
64
  {
61
- type: "input",
62
- name: "projectName",
63
- message: t("projectName"),
64
- default: "my-noshift-app",
65
+ type: "confirm",
66
+ name: "usePrettier",
67
+ message: "Format compiled output with Prettier?",
68
+ default: true,
65
69
  },
66
70
  ]);
67
- projectName = answer.projectName;
68
- }
69
71
 
70
- const projectPath = path.join(cwd, projectName);
71
- await fs.mkdir(projectPath, { recursive: true });
72
- console.log(`\n${t("creatingDir")} ${projectPath}`);
73
-
74
- process.chdir(projectPath);
75
-
76
- // npm init
77
- console.log(t("initializingNpm"));
78
- execSync("npm init -y", { stdio: "inherit" });
79
-
80
- // package.json に scripts を追加
81
- const pkgPath = path.join(projectPath, "package.json");
82
- const pkg = JSON.parse(await fs.readFile(pkgPath, "utf-8"));
83
- pkg.scripts = pkg.scripts ?? {};
84
- pkg.scripts.compile = "nsc compile";
85
- pkg.scripts.dev = "nsc dev";
86
- await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
87
-
88
- // nsjsconfig.json を作成
89
- const nsjsconfig = {
90
- compilerOptions: {
91
- rootDir: "src",
92
- outDir: "build",
93
- },
94
- };
95
- await fs.writeFile(
96
- "nsjsconfig.json",
97
- JSON.stringify(nsjsconfig, null, 2) + "\n",
98
- );
99
- console.log(t("creatingConfig"));
100
-
101
- // Prettier
102
- const { usePrettier } = await inquirer.prompt([
103
- {
104
- type: "confirm",
105
- name: "usePrettier",
106
- message: t("usePrettier"),
107
- default: true,
108
- },
109
- ]);
110
-
111
- if (usePrettier) {
112
- console.log(t("installingPrettier"));
113
- execSync("npm install --save-dev prettier", { stdio: "inherit" });
114
- await fs.writeFile(".prettierignore", "build/\nnode_modules/\n");
72
+ if (usePrettier) {
73
+ logger.step("Installing Prettier...");
74
+ execSync("npm install --save-dev prettier", { stdio: "ignore" });
75
+ await fs.writeFile(".prettierignore", "dist/\nnode_modules/\n");
76
+ await fs.writeFile(
77
+ ".prettierrc",
78
+ JSON.stringify(
79
+ { semi: true, singleQuote: false, trailingComma: "es5" },
80
+ null,
81
+ 2,
82
+ ) + "\n",
83
+ );
84
+ }
85
+
86
+ // Install noshift.js
87
+ logger.step("Installing noshift.js...");
88
+ execSync("npm install noshift.js", { stdio: "ignore" });
89
+
90
+ // Create project files
91
+ logger.step("Creating project files...");
92
+ await fs.mkdir("src", { recursive: true });
115
93
  await fs.writeFile(
116
- ".prettierrc",
117
- JSON.stringify(
118
- { semi: true, singleQuote: false, trailingComma: "es5" },
119
- null,
120
- 2,
121
- ) + "\n",
94
+ "src/index.nsjs",
95
+ "console.log^8^2Hello, World!^2^9;\n",
122
96
  );
123
- }
124
-
125
- // noshift.js をインストール
126
- console.log(t("installingNoshift"));
127
- execSync("npm install noshift.js", { stdio: "inherit" });
128
-
129
- // src/index.nsjs
130
- await fs.mkdir("src", { recursive: true });
131
- await fs.writeFile("src/index.nsjs", "console.log^8^2Hello, World!^2^9;\n");
132
97
 
133
- // README.md
134
- const readme =
135
- lang === "ja"
136
- ? `# ${projectName}
137
-
138
- [NoShift.js](https://github.com/otoneko1102/NoShift.js) プロジェクトです。
139
-
140
- ## コンパイル
141
-
142
- \`\`\`bash
143
- npm run compile
144
- \`\`\`
145
-
146
- ## 開発 (出力確認)
147
-
148
- \`\`\`bash
149
- npm run dev
150
- \`\`\`
151
- `
152
- : `# ${projectName}
98
+ // README.md
99
+ const readme = `# ${projectName}
153
100
 
154
101
  A [NoShift.js](https://github.com/otoneko1102/NoShift.js) project.
155
102
 
@@ -159,15 +106,27 @@ A [NoShift.js](https://github.com/otoneko1102/NoShift.js) project.
159
106
  npm run compile
160
107
  \`\`\`
161
108
 
162
- ## Dev (preview output)
109
+ ## Dev (watch mode)
163
110
 
164
111
  \`\`\`bash
165
112
  npm run dev
166
113
  \`\`\`
167
114
  `;
168
115
 
169
- await fs.writeFile("README.md", readme);
170
-
171
- console.log(`\n${t("success")}`);
172
- console.log(t("nextSteps").replace("{name}", projectName));
116
+ await fs.writeFile("README.md", readme);
117
+
118
+ // Success message
119
+ console.log("");
120
+ logger.success("Project created successfully!");
121
+ console.log("");
122
+ logger.info("Next steps:");
123
+ console.log(` ${logger.highlight(`cd ${projectName}`)}`);
124
+ console.log(` ${logger.highlight("npm run compile")}`);
125
+ console.log("");
126
+ } catch (error) {
127
+ if (isUserCancelled(error)) {
128
+ process.exit(0);
129
+ }
130
+ throw error;
131
+ }
173
132
  }
package/commands/dev.js CHANGED
@@ -2,6 +2,8 @@ import { promises as fs, watch } from "fs";
2
2
  import path from "path";
3
3
  import convert from "../src/convert.js";
4
4
  import { loadConfig } from "../src/config.js";
5
+ import { handleSigint } from "../src/signal-handler.js";
6
+ import * as logger from "../src/logger.js";
5
7
 
6
8
  function timestamp() {
7
9
  return new Date().toLocaleTimeString("en-GB"); // HH:MM:SS
@@ -36,7 +38,7 @@ async function compileFile(file, rootDir, outDir, cwd) {
36
38
  const js = convert(code);
37
39
  await fs.mkdir(path.dirname(destPath), { recursive: true });
38
40
  await fs.writeFile(destPath, js, "utf-8");
39
- console.log(
41
+ logger.dim(
40
42
  `[${timestamp()}] ${relative} → ${path.relative(cwd, destPath).replace(/\\/g, "/")}`,
41
43
  );
42
44
  }
@@ -48,7 +50,7 @@ export default async function dev() {
48
50
  try {
49
51
  config = await loadConfig(cwd);
50
52
  } catch (e) {
51
- console.error(`error NS0: ${e.message}`);
53
+ logger.errorCode("NS0", e.message);
52
54
  process.exit(1);
53
55
  }
54
56
 
@@ -58,13 +60,14 @@ export default async function dev() {
58
60
  // 初回フルコンパイル
59
61
  const files = await findNsjsFiles(rootDir);
60
62
  if (files === null) {
61
- console.error(
62
- `error NS0: rootDir '${config.compilerOptions.rootDir}' not found.`,
63
+ logger.errorCode(
64
+ "NS0",
65
+ `rootDir '${config.compilerOptions.rootDir}' not found.`,
63
66
  );
64
67
  process.exit(1);
65
68
  }
66
69
 
67
- console.log(`[${timestamp()}] Starting compilation in watch mode...`);
70
+ logger.info(`Starting compilation in watch mode...`);
68
71
 
69
72
  await fs.mkdir(outDir, { recursive: true });
70
73
 
@@ -73,13 +76,19 @@ export default async function dev() {
73
76
  await compileFile(file, rootDir, outDir, cwd);
74
77
  } catch (e) {
75
78
  const rel = path.relative(rootDir, file).replace(/\\/g, "/");
76
- console.error(`[${timestamp()}] error: ${rel}: ${e.message}`);
79
+ logger.errorCode("NS1", `${rel}: ${e.message}`);
77
80
  }
78
81
  }
79
82
 
80
- console.log(
81
- `[${timestamp()}] Watching for file changes in '${config.compilerOptions.rootDir}'...\n`,
83
+ logger.info(
84
+ `Watching for file changes in '${logger.highlight(config.compilerOptions.rootDir)}'... (Press Ctrl+C to stop)`,
82
85
  );
86
+ console.log("");
87
+
88
+ // Ctrl+C で終了
89
+ handleSigint(() => {
90
+ logger.info("Stopped watching.");
91
+ });
83
92
 
84
93
  // デバウンス用マップ (ファイルパス → タイマーID)
85
94
  const debounceMap = new Map();
@@ -105,8 +114,9 @@ export default async function dev() {
105
114
  if (e.code === "ENOENT") {
106
115
  // ファイルが削除された場合はスキップ
107
116
  } else {
108
- console.error(
109
- `[${timestamp()}] error: ${filename.replace(/\\/g, "/")}: ${e.message}`,
117
+ logger.errorCode(
118
+ "NS1",
119
+ `${filename.replace(/\\/g, "/")}: ${e.message}`,
110
120
  );
111
121
  }
112
122
  }
package/commands/init.js CHANGED
@@ -1,20 +1,25 @@
1
1
  import { writeFile, access } from "fs/promises";
2
2
  import path from "path";
3
+ import { handleSigint } from "../src/signal-handler.js";
4
+ import * as logger from "../src/logger.js";
3
5
 
4
6
  const DEFAULT_CONFIG = {
5
7
  compilerOptions: {
6
8
  rootDir: "src",
7
- outDir: "build",
9
+ outDir: "dist",
8
10
  },
9
11
  };
10
12
 
11
13
  export default async function init() {
14
+ handleSigint();
15
+
12
16
  const configPath = path.join(process.cwd(), "nsjsconfig.json");
13
17
 
14
18
  try {
15
19
  await access(configPath);
16
- console.error(
17
- "error NS4: nsjsconfig.json already exists in the current directory.",
20
+ logger.errorCode(
21
+ "NS4",
22
+ "nsjsconfig.json already exists in the current directory.",
18
23
  );
19
24
  process.exit(1);
20
25
  } catch {
@@ -22,7 +27,8 @@ export default async function init() {
22
27
  }
23
28
 
24
29
  await writeFile(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2) + "\n");
25
- console.log("Created nsjsconfig.json.");
26
- console.log("\n compilerOptions.rootDir : src");
27
- console.log(" compilerOptions.outDir : build\n");
30
+ logger.success("Created nsjsconfig.json");
31
+ logger.dim(` compilerOptions.rootDir : ${DEFAULT_CONFIG.compilerOptions.rootDir}`);
32
+ logger.dim(` compilerOptions.outDir : ${DEFAULT_CONFIG.compilerOptions.outDir}`);
33
+ console.log("");
28
34
  }
package/commands/run.js CHANGED
@@ -2,15 +2,19 @@ import { promises as fs } from "fs";
2
2
  import path from "path";
3
3
  import { spawn } from "child_process";
4
4
  import convert from "../src/convert.js";
5
+ import { handleSigint } from "../src/signal-handler.js";
6
+ import * as logger from "../src/logger.js";
5
7
 
6
8
  export default async function run(file) {
9
+ handleSigint();
10
+
7
11
  const filePath = path.resolve(process.cwd(), file);
8
12
 
9
13
  let code;
10
14
  try {
11
15
  code = await fs.readFile(filePath, "utf-8");
12
16
  } catch {
13
- console.error(`error NS2: File not found: ${filePath}`);
17
+ logger.errorCode("NS2", `File not found: ${filePath}`);
14
18
  process.exit(1);
15
19
  }
16
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "noshift.js",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Joke language.",
5
5
  "bin": {
6
6
  "nsc": "./bin/cli.js"
package/src/logger.js ADDED
@@ -0,0 +1,52 @@
1
+ // シンプルなロガーユーティリティ(ANSI エスケープコードを使用)
2
+
3
+ const colors = {
4
+ reset: "\x1b[0m",
5
+ bright: "\x1b[1m",
6
+ dim: "\x1b[2m",
7
+ red: "\x1b[31m",
8
+ green: "\x1b[32m",
9
+ yellow: "\x1b[33m",
10
+ blue: "\x1b[34m",
11
+ magenta: "\x1b[35m",
12
+ cyan: "\x1b[36m",
13
+ gray: "\x1b[90m",
14
+ };
15
+
16
+ export function success(message) {
17
+ console.log(`${colors.green}✓${colors.reset} ${message}`);
18
+ }
19
+
20
+ export function error(message) {
21
+ console.error(`${colors.red}✗${colors.reset} ${message}`);
22
+ }
23
+
24
+ export function info(message) {
25
+ console.log(`${colors.blue}ℹ${colors.reset} ${message}`);
26
+ }
27
+
28
+ export function warn(message) {
29
+ console.log(`${colors.yellow}⚠${colors.reset} ${message}`);
30
+ }
31
+
32
+ export function step(message) {
33
+ console.log(`${colors.cyan}→${colors.reset} ${message}`);
34
+ }
35
+
36
+ export function dim(message) {
37
+ console.log(`${colors.dim}${message}${colors.reset}`);
38
+ }
39
+
40
+ export function bold(text) {
41
+ return `${colors.bright}${text}${colors.reset}`;
42
+ }
43
+
44
+ export function highlight(text) {
45
+ return `${colors.cyan}${text}${colors.reset}`;
46
+ }
47
+
48
+ export function errorCode(code, message) {
49
+ console.error(
50
+ `${colors.red}error ${code}:${colors.reset} ${message}`,
51
+ );
52
+ }
@@ -0,0 +1,46 @@
1
+ // シグナルハンドリングユーティリティ
2
+
3
+ let isHandlerRegistered = false;
4
+ let cleanupCallbacks = [];
5
+
6
+ /**
7
+ * Ctrl+C (SIGINT) を適切にハンドリングする
8
+ * @param {Function} cleanup - クリーンアップ時に実行する関数(オプション)
9
+ */
10
+ export function handleSigint(cleanup) {
11
+ if (cleanup) {
12
+ cleanupCallbacks.push(cleanup);
13
+ }
14
+
15
+ if (!isHandlerRegistered) {
16
+ isHandlerRegistered = true;
17
+
18
+ process.on("SIGINT", async () => {
19
+ console.log("\n"); // 改行を追加してきれいに終了
20
+
21
+ // すべてのクリーンアップコールバックを実行
22
+ for (const cb of cleanupCallbacks) {
23
+ try {
24
+ await cb();
25
+ } catch (e) {
26
+ // エラーは無視
27
+ }
28
+ }
29
+
30
+ process.exit(0);
31
+ });
32
+ }
33
+ }
34
+
35
+ /**
36
+ * inquirer のキャンセルエラーをチェック
37
+ * @param {Error} error
38
+ * @returns {boolean}
39
+ */
40
+ export function isUserCancelled(error) {
41
+ return (
42
+ error &&
43
+ (error.name === "ExitPromptError" ||
44
+ error.message === "User force closed the prompt")
45
+ );
46
+ }