dongnelibrary 0.2.9 → 0.2.10

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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "engines": {
4
4
  "node": ">=18.0.0"
5
5
  },
6
- "version": "0.2.9",
6
+ "version": "0.2.10",
7
7
  "description": "책을 빌릴 수 있는지 확인한다.",
8
8
  "main": "src/dongnelibrary.js",
9
9
  "bin": {
package/src/cli.js CHANGED
@@ -1,9 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  const Configstore = require("configstore");
3
- const _ = require("lodash");
4
3
  const colors = require("colors");
5
4
  const figlet = require("figlet");
6
- const fp = require("lodash/fp");
7
5
  const inquirer = require("inquirer");
8
6
  const program = require("commander");
9
7
  const dl = require("./dongnelibrary");
@@ -11,11 +9,13 @@ const util = require("./util");
11
9
  const pkg = require("../package.json");
12
10
 
13
11
  const conf = new Configstore(pkg.name, {});
14
- const getDefaultLibrary = () => conf.get("library");
15
- const setDefaultLibrary = (name) => conf.set("library", name);
16
- const getDefaultTitle = () =>
17
- conf.get("title") === undefined ? "javascript" : conf.get("title");
18
- const setDefaultTitle = (title) => conf.set("title", title);
12
+
13
+ const config = {
14
+ getLibrary: () => conf.get("library"),
15
+ setLibrary: (name) => conf.set("library", name),
16
+ getTitle: () => conf.get("title") ?? "javascript",
17
+ setTitle: (title) => conf.set("title", title),
18
+ };
19
19
 
20
20
  const introMessage = (msg) => {
21
21
  console.log(
@@ -35,151 +35,121 @@ program
35
35
  .option("-t, --title [title]", "a part of book title")
36
36
  .parse(process.argv);
37
37
 
38
- function cutTail(str, tail) {
39
- let result = "";
38
+ const cutTail = (str, tail) => {
40
39
  const index = str.indexOf(tail);
41
- if (index === -1) {
42
- result = str;
43
- } else {
44
- result = str.substring(0, index);
40
+ return index === -1 ? str : str.substring(0, index);
41
+ };
42
+
43
+ const MARKS = {
44
+ ok: "✓ ",
45
+ notOk: "✖ ",
46
+ };
47
+
48
+ const printBooks = ({ booklist }) => {
49
+ for (const { libraryName, exist, title, bookUrl } of booklist) {
50
+ const mark = exist ? ` ${MARKS.ok} ` : ` ${colors.red(MARKS.notOk)} `;
51
+ console.log(`${cutTail(libraryName, "도서관")}${mark}${title}`);
52
+ if (bookUrl) {
53
+ console.log(` → ${colors.cyan(bookUrl)}`);
54
+ }
45
55
  }
46
- return result;
47
- }
48
-
49
- const okMark = "✓ ";
50
- const notokMark = "✖ ";
51
-
52
- function printBooks(book) {
53
- _.each(book.booklist, (book) => {
54
- console.log(
55
- cutTail(book.libraryName, "도서관") +
56
- (book.exist ? " " + okMark + " " : " " + colors.red(notokMark) + " ") +
57
- book.title +
58
- " ",
59
- );
60
- });
61
- }
56
+ };
62
57
 
63
- function printAllLibraryName() {
58
+ const printAllLibraryNames = () => {
64
59
  const libs = dl.getLibraryNames();
65
- libs.forEach((name) => {
66
- console.log(name);
67
- });
68
- const msg = `모두 ${libs.length} 개의 도서관`;
69
- console.log(colors.green(msg));
70
- }
60
+ libs.forEach((name) => console.log(name));
61
+ console.log(colors.green(`모두 ${libs.length} 개의 도서관`));
62
+ };
71
63
 
72
64
  const getFullLibraryName = (str) =>
73
- _.find(dl.getLibraryNames(), (name) => name.indexOf(str) >= 0);
74
-
75
- function search(option, bookCallback, allBookCallback) {
76
- dl.search(
77
- {
78
- title: option.title,
79
- libraryName: getLibraries(option.libraryName),
80
- },
81
- (err, book) => {
82
- if (err) {
83
- err.msg = err.msg || "Unknown Error";
84
- if (bookCallback) {
85
- bookCallback(err);
86
- }
87
- } else {
88
- if (bookCallback) {
89
- bookCallback(null, book);
90
- }
91
- }
92
- },
93
- (err, books) => {
94
- if (err) {
95
- err.msg = err.msg || "Unknown Error";
96
- if (allBookCallback) {
97
- allBookCallback(err);
98
- }
99
- } else {
100
- if (allBookCallback) {
101
- allBookCallback(null, books);
102
- }
103
- }
104
- },
105
- );
106
- }
65
+ dl.getLibraryNames().find((name) => name.includes(str));
107
66
 
108
67
  const getBookCount = (results) =>
109
- _.reduce(
110
- results,
111
- (memo, book) =>
112
- memo +
113
- (book && book.booklist && book.booklist.length
114
- ? book.booklist.length
115
- : 0),
116
- 0,
117
- );
68
+ results.reduce((sum, book) => sum + (book?.booklist?.length ?? 0), 0);
118
69
 
119
- const getLibraryFullNameList = _.flow([
120
- util.getArrayFromCommaSeparatedString,
121
- fp.filter((shortLibraryName) => getFullLibraryName(shortLibraryName)),
122
- ]);
70
+ const getLibraryFullNameList = (libraryName) =>
71
+ util
72
+ .getArrayFromCommaSeparatedString(libraryName)
73
+ .filter((name) => getFullLibraryName(name));
123
74
 
124
75
  const getLibraries = (libraryName) =>
125
76
  libraryName ? getLibraryFullNameList(libraryName) : dl.getLibraryNames();
126
77
 
127
- const processOneLibrary = (err, book) => {
128
- if (err) {
129
- console.log(err.msg);
130
- } else {
131
- printBooks(book);
132
- }
78
+ const searchLibraries = ({ title, libraryName }) =>
79
+ new Promise((resolve) => {
80
+ const results = [];
81
+ dl.search(
82
+ { title, libraryName: getLibraries(libraryName) },
83
+ (err, book) => {
84
+ if (err) {
85
+ console.log(err.msg ?? "Unknown Error");
86
+ } else {
87
+ printBooks(book);
88
+ results.push(book);
89
+ }
90
+ },
91
+ (err, allBooks) => {
92
+ if (err) {
93
+ console.log("Error, Can't access detail information");
94
+ resolve([]);
95
+ } else {
96
+ resolve(allBooks);
97
+ }
98
+ },
99
+ );
100
+ });
101
+
102
+ const printSearchSummary = (results) => {
103
+ const bookCount = getBookCount(results);
104
+ console.log(
105
+ colors.green(`${results.length} 개의 도서관에서 ${bookCount} 권 검색됨`),
106
+ );
133
107
  };
134
108
 
135
- const processLibraries = (err, results) => {
136
- if (err) {
137
- console.log("Error, Can't access detail information");
138
- } else {
139
- console.log(
140
- colors.green(
141
- `${results.length} 개의 도서관에서 ${getBookCount(results)} 권 검색됨`,
142
- ),
143
- );
144
- }
109
+ const promptForSearchOptions = async () => {
110
+ introMessage("Dongne Library");
111
+ const { library, title } = await inquirer.prompt([
112
+ {
113
+ type: "list",
114
+ name: "library",
115
+ message: "도서관 이름은?",
116
+ choices: dl.getLibraryNames(),
117
+ default: config.getLibrary(),
118
+ },
119
+ {
120
+ type: "input",
121
+ name: "title",
122
+ message: "책 이름은?",
123
+ default: config.getTitle(),
124
+ },
125
+ ]);
126
+
127
+ config.setLibrary(library);
128
+ config.setTitle(title);
129
+
130
+ return { libraryName: library, title };
145
131
  };
146
132
 
147
- function activate(option) {
148
- if (option.libraryList) {
149
- printAllLibraryName(option);
133
+ const activate = async () => {
134
+ const { libraryList, interactive, libraryName, title } = program;
135
+
136
+ if (libraryList) {
137
+ printAllLibraryNames();
150
138
  return;
151
139
  }
152
140
 
153
- if (option.interactive) {
154
- introMessage("Dongne Library");
155
- inquirer
156
- .prompt([
157
- {
158
- type: "list",
159
- name: "library",
160
- message: "도서관 이름은?",
161
- choices: dl.getLibraryNames(),
162
- default: getDefaultLibrary(),
163
- },
164
- {
165
- type: "input",
166
- name: "title",
167
- message: "책 이름은?",
168
- default: getDefaultTitle(),
169
- },
170
- ])
171
- .then((answers) => {
172
- option.libraryName = answers["library"];
173
- option.title = answers["title"];
174
- setDefaultLibrary(option.libraryName);
175
- setDefaultTitle(option.title);
176
- if (option.libraryName && option.title) {
177
- search(option, processOneLibrary, processLibraries);
178
- }
179
- });
180
- } else if (option.libraryName && option.title) {
181
- search(option, processOneLibrary, processLibraries);
141
+ let searchOptions;
142
+
143
+ if (interactive) {
144
+ searchOptions = await promptForSearchOptions();
145
+ } else if (libraryName && title) {
146
+ searchOptions = { libraryName, title };
147
+ } else {
148
+ return;
182
149
  }
183
- }
184
150
 
185
- activate(program);
151
+ const results = await searchLibraries(searchOptions);
152
+ printSearchSummary(results);
153
+ };
154
+
155
+ activate();
@@ -1,5 +1,3 @@
1
- const _ = require("lodash");
2
- const fp = require("lodash/fp");
3
1
  const gg = require("./library/gg");
4
2
  const gunpo = require("./library/gunpo");
5
3
  const hscity = require("./library/hscity");
@@ -7,134 +5,93 @@ const osan = require("./library/osan");
7
5
  const snlib = require("./library/snlib");
8
6
  const suwon = require("./library/suwon");
9
7
  const yongin = require("./library/yongin");
10
- const async = require("async");
11
8
  const util = require("./util.js");
12
9
 
13
- const libraryList = [];
10
+ const LIBRARY_MODULES = [gg, gunpo, hscity, osan, snlib, suwon, yongin];
11
+
12
+ const libraryList = LIBRARY_MODULES.flatMap((module) =>
13
+ module.getLibraryNames().map((name) => ({
14
+ name,
15
+ search: module.search,
16
+ })),
17
+ );
14
18
 
15
19
  const getLibraryNames = () => util.getLibraryNames(libraryList);
16
20
 
17
- function makeLibraryList() {
18
- const library = [gg, gunpo, hscity, osan, snlib, suwon, yongin];
21
+ const UNKNOWN_LIBRARY = {
22
+ name: "Unknown",
23
+ search: (opt, getBook) => getBook?.({ msg: "Unknown library name" }),
24
+ };
19
25
 
20
- _.each(library, (library) => {
21
- _.each(library.getLibraryNames(), (name) => {
22
- libraryList.push({
23
- name,
24
- search: library.search,
25
- });
26
- });
27
- });
28
- }
26
+ const getLibraryFunction = (libraryName) =>
27
+ libraryList.find((lib) => lib.name === libraryName) ?? UNKNOWN_LIBRARY;
29
28
 
30
- const getLibraryFunction = (libraryName) => {
31
- const found = _.find(libraryList, (lib) => lib.name === libraryName);
32
- return found
33
- ? found
34
- : {
35
- search: (opt, getBook) => {
36
- if (getBook) {
37
- getBook({ msg: "Unknown library name" });
38
- }
39
- },
40
- name: "Unknown",
41
- };
42
- };
29
+ const completeLibraryName = (str) =>
30
+ getLibraryNames().find((name) => name.includes(str)) ?? "";
43
31
 
44
- function completeLibraryName(str) {
45
- const found = _.find(getLibraryNames(), (name) => name.indexOf(str) >= 0);
46
- return found ? found : "";
47
- }
32
+ const isValidLibraryName = (libraryName) =>
33
+ libraryList.some((lib) => lib.name === libraryName);
48
34
 
49
- function isValidLibraryName(libraryName) {
50
- const found = _.find(libraryList, (lib) => lib.name === libraryName);
51
- return found ? true : false;
52
- }
35
+ const getLibArray = (libraryName) => {
36
+ const names = Array.isArray(libraryName) ? libraryName : [libraryName];
37
+ return names
38
+ .map((name) => completeLibraryName(name))
39
+ .filter((fullName) => isValidLibraryName(fullName))
40
+ .map((fullName) => getLibraryFunction(fullName));
41
+ };
53
42
 
54
- function getLibArray(libraryName) {
55
- return _.flow([
56
- fp.map((name) => {
57
- const fullName = completeLibraryName(name);
58
- return isValidLibraryName(fullName) ? getLibraryFunction(fullName) : null;
59
- }),
60
- _.compact,
61
- ])(Array.isArray(libraryName) ? libraryName : [libraryName]);
62
- }
43
+ const getSortedBooks = (books) =>
44
+ books
45
+ .map(({ libraryName, title, exist, bookUrl }) => ({ libraryName, title, exist, bookUrl }))
46
+ .sort((a, b) => (a.exist === b.exist ? 0 : a.exist ? -1 : 1));
63
47
 
64
- const getSortedBooks = _.flow([
65
- fp.map((book) => ({
66
- libraryName: book.libraryName,
67
- title: book.title,
68
- exist: book.exist,
69
- })),
70
- fp.sortBy((book) => !book.exist),
71
- ]);
48
+ const searchLibrary = (lib, title) =>
49
+ new Promise((resolve) => {
50
+ lib.search({ title, libraryName: lib.name }, (err, data) => {
51
+ if (err) {
52
+ resolve({ error: err });
53
+ return;
54
+ }
55
+ if (!data?.booklist) {
56
+ resolve({ error: { msg: "invalid Data response" } });
57
+ return;
58
+ }
59
+ resolve({
60
+ result: {
61
+ title,
62
+ libraryName: lib.name,
63
+ totalBookCount: data.totalBookCount,
64
+ startPage: data.startPage,
65
+ booklist: getSortedBooks(data.booklist),
66
+ },
67
+ });
68
+ });
69
+ });
72
70
 
73
- function search(opt, getBook, getAllBooks) {
71
+ const search = (opt, getBook, getAllBooks) => {
74
72
  if (!opt || (!getBook && !getAllBooks)) {
75
73
  console.log("invalid search options");
76
74
  return;
77
75
  }
78
76
 
79
- const title = opt.title;
80
- const tasks = [];
81
-
82
- _.each(getLibArray(opt.libraryName), (lib) => {
83
- tasks.push((callback) => {
84
- lib.search(
85
- {
86
- title: title,
87
- libraryName: lib.name,
88
- },
89
- (err, data) => {
90
- if (err) {
91
- if (getBook) {
92
- getBook(err);
93
- }
94
- callback(err);
95
- return;
96
- }
97
- if (!data || !data.booklist) {
98
- if (getBook) {
99
- getBook({ msg: "invalid Data response" });
100
- }
101
- callback({ msg: "invalid Data response" });
102
- return;
103
- }
104
-
105
- const bookObj = {
106
- title: title,
107
- libraryName: lib.name,
108
- totalBookCount: data.totalBookCount,
109
- startPage: data.startPage,
110
- booklist: getSortedBooks(data.booklist),
111
- };
77
+ const { title, libraryName } = opt;
78
+ const libraries = getLibArray(libraryName);
112
79
 
113
- if (getBook) {
114
- getBook(null, bookObj);
115
- }
116
- callback(null, bookObj);
117
- },
118
- );
119
- });
120
- });
121
-
122
- async.parallel(tasks, (err, results) => {
123
- if (getAllBooks) {
124
- if (err) {
125
- getAllBooks(err);
126
- } else {
127
- getAllBooks(null, results);
128
- }
80
+ const promises = libraries.map(async (lib) => {
81
+ const { error, result } = await searchLibrary(lib, title);
82
+ if (error) {
83
+ getBook?.(error);
84
+ return null;
129
85
  }
86
+ getBook?.(null, result);
87
+ return result;
130
88
  });
131
- }
132
89
 
133
- function activate() {
134
- makeLibraryList();
135
- }
136
-
137
- activate();
90
+ Promise.all(promises).then((results) => {
91
+ const validResults = results.filter(Boolean);
92
+ getAllBooks?.(null, validResults);
93
+ });
94
+ };
138
95
 
139
96
  module.exports = {
140
97
  search,