diff --git a/src/client/pages/items/show.tsx b/src/client/pages/items/show.tsx
index 89843fd..3fd9d43 100644
--- a/src/client/pages/items/show.tsx
+++ b/src/client/pages/items/show.tsx
@@ -124,7 +124,7 @@ export const ItemsShow = () => {
error
-
{errorMessage}
+ {errorMessage}
))}
@@ -184,7 +184,3 @@ const errorStyle = css({
display: "flex",
marginTop: getSpace(3 / 2),
});
-
-const errorMessageBodyStyle = css({
- whiteSpace: "pre",
-});
diff --git a/src/commands/index.ts b/src/commands/index.ts
index 572baa3..b6d4074 100644
--- a/src/commands/index.ts
+++ b/src/commands/index.ts
@@ -1,3 +1,4 @@
+import { handleError } from "../lib/error-handler";
import { packageUpdateNotice } from "../lib/package-update-notice";
import { help, helpText } from "./help";
import { init } from "./init";
@@ -38,5 +39,11 @@ export const exec = async (commandName: string, commandArgs: string[]) => {
console.log(updateMessage);
}
- commands[commandName](commandArgs);
+ try {
+ await commands[commandName](commandArgs);
+ } catch (err) {
+ console.error(err);
+ await handleError(err as Error);
+ process.exit(1);
+ }
};
diff --git a/src/commands/publish.ts b/src/commands/publish.ts
index 91b29fa..2b0e9fa 100644
--- a/src/commands/publish.ts
+++ b/src/commands/publish.ts
@@ -65,10 +65,15 @@ export const publish = async (argv: string[]) => {
return acc;
}, [] as { name: string; errors: string[] }[]);
if (invalidItemMessages.length > 0) {
- console.error("Validation error:");
+ const chalk = (await import("chalk")).default;
invalidItemMessages.forEach((msg) => {
- console.error(msg.name, msg.errors);
+ msg.errors.forEach((err) => {
+ const errorName = chalk.red.bold(msg.name + ":");
+ const errorDescription = chalk.red(err);
+ console.error(`${errorName} ${errorDescription}`);
+ });
});
+
process.exit(1);
}
diff --git a/src/lib/check-frontmatter-type.ts b/src/lib/check-frontmatter-type.ts
index 2f98e39..00d077f 100644
--- a/src/lib/check-frontmatter-type.ts
+++ b/src/lib/check-frontmatter-type.ts
@@ -65,7 +65,7 @@ const checkOrganizationUrlName: CheckType = {
const checkSlide: CheckType = {
getMessage: () =>
- "slideの設定はtrue/falseで入力してください\n\n【破壊的な変更がありました】\n詳しくは以下のリリースをご確認ください\nhttps://github.com/increments/qiita-cli/releases/tag/v0.5.0",
+ "slideの設定はtrue/falseで入力してください(破壊的な変更がありました。詳しくはリリースをご確認ください https://github.com/increments/qiita-cli/releases/tag/v0.5.0)",
isValid: ({ slide }) => {
return typeof slide === "boolean";
},
diff --git a/src/lib/error-handler.ts b/src/lib/error-handler.ts
new file mode 100644
index 0000000..a3939ac
--- /dev/null
+++ b/src/lib/error-handler.ts
@@ -0,0 +1,86 @@
+import {
+ QiitaBadRequestError,
+ QiitaFetchError,
+ QiitaForbiddenError,
+ QiitaInternalServerError,
+ QiitaNotFoundError,
+ QiitaRateLimitError,
+ QiitaUnauthorizedError,
+ QiitaUnknownError,
+} from "../qiita-api";
+
+export const handleError = async (error: Error) => {
+ const chalk = (await import("chalk")).default;
+
+ switch (error.name) {
+ // Qiita API
+ case QiitaFetchError.name:
+ console.error(
+ chalk.red.bold(
+ "Qiita APIへのリクエストでネットワークエラーが発生しました"
+ )
+ );
+ console.error(
+ chalk.red(" インターネットに接続されているかご確認ください")
+ );
+ break;
+ case QiitaBadRequestError.name:
+ console.error(chalk.red.bold("Qiita APIへのリクエストに失敗しました"));
+ console.error(chalk.red(" 記事ファイルに不備がないかご確認ください"));
+ break;
+ case QiitaUnauthorizedError.name:
+ console.error(chalk.red.bold("Qiitaの認証に失敗しました"));
+ console.error(
+ chalk.red(" loginコマンドでQiitaにログインしているかご確認ください")
+ );
+ console.error(
+ chalk.red(" Qiitaのアクセストークンが正しいかご確認ください")
+ );
+ break;
+ case QiitaForbiddenError.name:
+ console.error(chalk.red.bold("Qiita APIへのリクエストに失敗しました"));
+ console.error(
+ chalk.red(" Qiitaのアクセストークンが正しいかご確認ください")
+ );
+ console.error(chalk.red(""));
+ break;
+ case QiitaNotFoundError.name:
+ console.error(chalk.red.bold("記事が見つかりませんでした"));
+ console.error(
+ chalk.red(" Qiita上で記事が削除されていないかご確認ください")
+ );
+ break;
+ case QiitaRateLimitError.name:
+ console.error(chalk.red.bold("Qiita APIのレートリミットに達しました"));
+ console.error(chalk.red(" しばらく時間を置いてから再度お試しください"));
+ break;
+ case QiitaInternalServerError.name:
+ console.error(chalk.red.bold("Qiitaのサーバーでエラーが発生しました"));
+ console.error(chalk.red(" しばらく時間を置いてから再度お試しください"));
+ break;
+ case QiitaUnknownError.name:
+ console.error(
+ chalk.red.bold("Qiita APIへのリクエストで不明なエラーが発生しました")
+ );
+ console.error(
+ chalk.red(
+ " バグの可能性がある場合は、Qiita Discussionsよりご報告いただけると幸いです"
+ )
+ );
+ console.error(
+ chalk.red(" https://github.com/increments/qiita-discussions")
+ );
+ break;
+
+ default:
+ console.error(chalk.red.bold(`エラーが発生しました (${error.message})`));
+ console.error(
+ chalk.red(
+ " バグの可能性がある場合は、Qiita Discussionsよりご報告いただけると幸いです"
+ )
+ );
+ console.error(
+ chalk.red(" https://github.com/increments/qiita-discussions")
+ );
+ }
+};
diff --git a/src/qiita-api/errors.ts b/src/qiita-api/errors.ts
new file mode 100644
index 0000000..f925eaa
--- /dev/null
+++ b/src/qiita-api/errors.ts
@@ -0,0 +1,55 @@
+export class QiitaFetchError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = "QiitaFetchError";
+ }
+}
+
+export class QiitaBadRequestError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = "QiitaBadRequestError";
+ }
+}
+
+export class QiitaUnauthorizedError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = "QiitaUnauthorizedError";
+ }
+}
+
+export class QiitaForbiddenError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = "QiitaForbiddenError";
+ }
+}
+
+export class QiitaNotFoundError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = "QiitaNotFoundError";
+ }
+}
+
+export class QiitaRateLimitError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = "QiitaRateLimitError";
+ }
+}
+
+export class QiitaInternalServerError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = "QiitaInternalServerError";
+ }
+}
+
+export class QiitaUnknownError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = "QiitaUnknownError";
+ }
+}
diff --git a/src/qiita-api/index.ts b/src/qiita-api/index.ts
index 7571661..655e9ee 100644
--- a/src/qiita-api/index.ts
+++ b/src/qiita-api/index.ts
@@ -1,6 +1,18 @@
import { URL, URLSearchParams } from "node:url";
+import {
+ QiitaBadRequestError,
+ QiitaFetchError,
+ QiitaForbiddenError,
+ QiitaInternalServerError,
+ QiitaNotFoundError,
+ QiitaRateLimitError,
+ QiitaUnauthorizedError,
+ QiitaUnknownError,
+} from "./errors";
import { qiitaApiDebugger } from "./lib/debugger";
+export * from "./errors";
+
export interface Item {
body: string;
id: string;
@@ -65,7 +77,7 @@ export class QiitaApi {
});
} catch (err) {
console.error(err);
- throw new Error("NetworkError");
+ throw new QiitaFetchError((err as Error).message);
}
if (response.ok) {
@@ -78,8 +90,8 @@ export class QiitaApi {
}
}
+ const responseBody = await response.text();
if (qiitaApiDebugger.enabled) {
- const responseBody = await response.text();
qiitaApiDebugger(
"request failed",
JSON.stringify({
@@ -89,21 +101,22 @@ export class QiitaApi {
);
}
+ const errorMessage = responseBody.slice(0, 100);
switch (response.status) {
case 400:
- throw new Error("QiitaBadRequestError");
+ throw new QiitaBadRequestError(errorMessage);
case 401:
- throw new Error("QiitaUnauthorizedError");
+ throw new QiitaUnauthorizedError(errorMessage);
case 403:
- throw new Error("QiitaForbiddenError");
+ throw new QiitaForbiddenError(errorMessage);
case 404:
- throw new Error("QiitaNotFoundError");
+ throw new QiitaNotFoundError(errorMessage);
case 429:
- throw new Error("QiitaRateLimitError");
+ throw new QiitaRateLimitError(errorMessage);
case 500:
- throw new Error("QiitaInternalServerError");
+ throw new QiitaInternalServerError(errorMessage);
default:
- throw new Error("QiitaUnknownError");
+ throw new QiitaUnknownError(errorMessage);
}
}
diff --git a/src/server/app.ts b/src/server/app.ts
index 4d97fd1..9f2de35 100644
--- a/src/server/app.ts
+++ b/src/server/app.ts
@@ -35,7 +35,7 @@ export async function startServer() {
const port = userConfig.port;
const host = "localhost";
- return new Promise((resolve) => {
+ return new Promise((resolve, reject) => {
server
.listen(port, host)
.once("listening", () => {
@@ -43,8 +43,8 @@ export async function startServer() {
resolve(server);
})
- .once("error", () => {
- throw new Error("Failed to start server");
+ .once("error", (err) => {
+ reject(err);
});
});
}