Skip to content

Instantly share code, notes, and snippets.

@typebird
Last active April 6, 2020 09:08
Show Gist options
  • Save typebird/be9bc2e8f84a2c94f3935b9d06176319 to your computer and use it in GitHub Desktop.
Save typebird/be9bc2e8f84a2c94f3935b9d06176319 to your computer and use it in GitHub Desktop.
一個簡單的終端機待辦表小程式。
const rl = require("readline").createInterface({
input: process.stdin,
output: process.stdout,
})
const path = require("path")
const fs = require("fs")
const SAVE_PATH = path.join(__dirname, "./save.txt")
/** @returns {Promise<String>} */
const interactive = que =>
new Promise(resolve => rl.question(que + "\n", resolve))
const File = (() => {
const basicMethod = {
/** @returns {Promise<[{id: Int, time: Int, data: String, done: Boolean}]>} */
read: () => new Promise((resolve, reject) =>
fs.readFile(SAVE_PATH, (err, data) => err
? reject(err)
: resolve(JSON.parse(data)))),
/** @returns {Promise<[{id: Int, time: Int, data: String, done: Boolean}]>} */
write: content => new Promise(resolve =>
fs.writeFile(SAVE_PATH, JSON.stringify(content), () => resolve(content))),
}
const append = content => {
const maxId = list => Math.max(...list.map(({ id }) => id))
const pushToLast = val => list => [
...list, (val.id = maxId(list) + 1, val)
]
return basicMethod.read()
.then(pushToLast(content))
.then(basicMethod.write)
}
const map = func => basicMethod.read()
.then(list => list.map(func))
.then(basicMethod.write)
return {
...basicMethod, append, map,
}
})()
const Data = {
init: val => ({ time: new Date().getTime(), data: val, done: false, }),
/** @returns {String} */
show: fileContent => fileContent.length === 0
? "Empty."
: fileContent
.map(({ time, data, done, id }) =>
`${done ? "[v]" : "[ ]"} [${id}]: ${data}\n\tat: ${new Date(time).toLocaleString()}`)
.join("\n")
}
const Parm = (() => {
const helpIntro = `
Hi, this is a simple todo list cli app.
Here have some function for you, try it out!
add <string> : add a todo in your list.
del <int?> : delete a todo that id is equal your parm.
: if didn't send any number to me, than I will delete all the list.
lok : display your todo list.
finish <int> : set a todo item are finish.`
const alog = todoList => Promise
.resolve(console.log("\n" + Data.show(todoList)))
const method = {
add: content => content
? Promise.resolve(Data.init(content))
.then(File.append)
.then(alog)
: Promise.resolve(console.log(
"You didn't input any content, I can't append that for you.")),
del: content => content
? File.read()
.then(data => data
.filter(({ id }) => id !== Number(content)))
.then(File.write)
.then(alog)
: Promise.resolve(console.log(
"You realy want to delete all todo list?"))
.then(() => interactive("If truely, input 'y' or 'Y':"))
.then(input => input === "y" || input === "Y"
? File.write([])
.then(() => console.log(
"Ok, now you have a new todo list."))
: console.log("Ok, I willn't change anything.")),
lok: () => File.read()
.then(alog),
finish: val => !Number.isNaN(Number(val))
? File.map(todo => todo.id === Number(val)
? (todo.done = true, todo)
: todo)
.then(alog)
: Promise.resolve(console.log(
"Your parm isn't a number, so I not sure what are your want.")),
help: () => Promise.resolve(console.log(helpIntro)),
}
return {
check: ([execute, ...content]) =>
(method[execute] || method.help)(content.join(" "))
}
})()
const main = (nodePath, filePath, ...userVals) =>
Parm.check(userVals)
.finally(() => rl.close())
main(...process.argv)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment