@kokiito0926/superhacker 0.0.3 → 0.0.4

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.
Files changed (2) hide show
  1. package/index.js +51 -17
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -11,8 +11,17 @@ const BASE_URL = "https://hacker-news.firebaseio.com/v0";
11
11
 
12
12
  async function getItem(id) {
13
13
  if (!id) return null;
14
- const res = await fetch(`${BASE_URL}/item/${id}.json`);
15
- return res.json();
14
+ try {
15
+ const res = await fetch(`${BASE_URL}/item/${id}.json`);
16
+ if (!res.ok) {
17
+ console.error(`Error fetching item ${id}: ${res.statusText}`);
18
+ return null;
19
+ }
20
+ return await res.json();
21
+ } catch (error) {
22
+ console.error(`Error fetching item ${id}: ${error.message}`);
23
+ return null;
24
+ }
16
25
  }
17
26
 
18
27
  async function getCommentsRecursive(ids, allComments = []) {
@@ -32,27 +41,42 @@ async function getCommentsRecursive(ids, allComments = []) {
32
41
  }
33
42
 
34
43
  function buildTree(list, parentId) {
35
- return list
36
- .filter((item) => item.parent === parentId)
37
- .map((item) => ({
38
- ...item,
39
- replies: buildTree(list, item.id),
40
- }));
44
+ const map = new Map();
45
+ for (const item of list) {
46
+ map.set(item.id, { ...item, replies: [] });
47
+ }
48
+
49
+ const tree = [];
50
+ for (const item of list) {
51
+ if (item.parent === parentId) {
52
+ tree.push(map.get(item.id));
53
+ } else {
54
+ const parent = map.get(item.parent);
55
+ if (parent) {
56
+ parent.replies.push(map.get(item.id));
57
+ }
58
+ }
59
+ }
60
+ return tree;
41
61
  }
42
62
 
43
63
  const command = argv._[0];
44
64
  if (!command) {
45
- console.error(`Error: Command is required.`);
65
+ console.error(`Error: Command is required (list, comment, comments).`);
46
66
  process.exit(1);
47
67
  }
48
68
  // console.log(command);
49
69
 
50
- const id = argv?.id;
70
+ const id = argv?.id ? parseInt(argv.id) : null;
51
71
  const limit = argv?.limit ? parseInt(argv?.limit) : null;
52
72
  const flat = argv?.format ? argv?.format === "flat" : false;
53
73
 
54
74
  if (command === "list") {
55
75
  const idsResponse = await fetch(`${BASE_URL}/topstories.json`);
76
+ if (!idsResponse.ok) {
77
+ console.error(`Error fetching top stories: ${idsResponse.statusText}`);
78
+ process.exit(1);
79
+ }
56
80
  let ids = await idsResponse.json();
57
81
 
58
82
  if (limit > 0) {
@@ -60,26 +84,32 @@ if (command === "list") {
60
84
  }
61
85
 
62
86
  const stories = await Promise.all(ids.map((id) => getItem(id)));
63
- const sortedStories = stories.sort((a, b) => b.score - a.score);
87
+ const sortedStories = stories
88
+ .filter((s) => s !== null)
89
+ .sort((a, b) => (b.score || 0) - (a.score || 0));
64
90
 
65
91
  console.log(JSON.stringify(sortedStories, null, 2));
66
- } else if (command === "comment") {
92
+ } else if (command === "comment" || command === "item") {
67
93
  if (!id) {
68
- console.error("Error: ID is required via --id or stdin.");
94
+ console.error("Error: ID is required via --id.");
69
95
  process.exit(1);
70
96
  }
71
97
  const item = await getItem(id);
98
+ if (!item) {
99
+ console.error(`Error: Item ${id} not found.`);
100
+ process.exit(1);
101
+ }
72
102
  console.log(JSON.stringify(item, null, 2));
73
103
  } else if (command === "comments") {
74
104
  if (!id) {
75
- console.error("Error: Story ID is required.");
105
+ console.error("Error: Story/Comment ID is required via --id.");
76
106
  process.exit(1);
77
107
  }
78
108
 
79
109
  const rootItem = await getItem(id);
80
110
  if (!rootItem) {
81
- console.log(JSON.stringify([]));
82
- process.exit(0);
111
+ console.error(`Error: Root item ${id} not found.`);
112
+ process.exit(1);
83
113
  }
84
114
 
85
115
  const flatComments = rootItem.kids ? await getCommentsRecursive(rootItem.kids) : [];
@@ -88,15 +118,19 @@ if (command === "list") {
88
118
  if (flat) {
89
119
  console.log(JSON.stringify([rootItem, ...flatComments], null, 2));
90
120
  } else {
121
+ const tree = buildTree(flatComments, id);
91
122
  console.log(
92
123
  JSON.stringify(
93
124
  {
94
125
  ...rootItem,
95
- replies: buildTree(flatComments, parseInt(id)),
126
+ replies: tree,
96
127
  },
97
128
  null,
98
129
  2,
99
130
  ),
100
131
  );
101
132
  }
133
+ } else {
134
+ console.error(`Error: Unknown command "${command}". Available commands: list, comment, comments.`);
135
+ process.exit(1);
102
136
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kokiito0926/superhacker",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "private": false,
5
5
  "description": "Hacker NewsのAPIを利用して、ストーリーやコメントをJSON形式で取得することができるコマンドラインのツールです。",
6
6
  "keywords": [