Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions oop/ErrorConstant.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const ERR_MSG = {
"NO_SHELL" : "명령어에 $를 포함시켜주세요.",
"INCORRECT_INST" : "사용가능한 명령어는 add | update | delete | show 입니다.",
"PARAMETER_ERROR" : "해당 명령어의 매게변수가 잘못되었습니다.",
"NOT_EXIST_ID" : "존재하지 않는 아이디입니다.",
"INCORRECT_STATUS" : "사용가능한 [[status]] 는 todo | doing | done 입니다.",
"SAME_STATUS" : "같은 상태로 업데이트가 불가능합니다.",
"TAG_SHAPE_ERROR" : "올바른 태그 형식이 아닙니다.",
"NO_MORE_REDO" : "더 이상 redo 할 수 없습니다.",
"NO_MORE_UNDO" : "더 이상 undo 할 수 없습니다.",
}

module.exports = {
ERR_MSG
}
154 changes: 154 additions & 0 deletions oop/Todos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
const validator = require('./validator.js')
const todoList = []

const historyQueue = {
data: [],
maxLength: 4,
pointer: 0,
recordTodo: function() {
this.data[this.pointer]={
todoList: JSON.parse(JSON.stringify([...todoList])),
}
if(this.pointer === 3) {
this.data.shift()
} else {
this.pointer++
}
this.data.length = this.pointer
},
undo: function(){
if (this.pointer <= 0) {
throw Error("NO_MORE_UNDO")
}
if(this.pointer === this.data.length){
this.data[this.pointer]={
todoList: JSON.parse(JSON.stringify([...todoList])),
}
}
this.pointer--
return this.data[this.pointer]
},
redo: function(){
if(this.pointer >= this.maxLength || this.pointer + 1 >= this.data.length) {
throw Error("NO_MORE_REDO")
}
this.pointer++
return this.data[this.pointer]
}
}

let incrementId = 0

const todoUtils = {
sleep: function (msec) {
return new Promise(resolve => setTimeout(resolve, msec))
},
generateId: function () {
return incrementId++
},
getListByStatus: function (status) {
return todoList.filter(el => el.status === status)
},
getCountByStatus: function (status) {
return todoList.filter(el => el.status === status).length
},
getAllStr: function () {
let str = "현재 상태 : "
const counts = {
"todo": this.getCountByStatus("todo"),
"doing": this.getCountByStatus("doing"),
"done": this.getCountByStatus("done")
}
str += Object.entries(counts).map(([k, v]) => `${k}: ${v}개`).join(", ")
return str
},
getStatusStr: function (status) {
let str = ""
let count = this.getCountByStatus(status)
let list = this.getListByStatus(status)
str += `${status}리스트 : 총${count}건 : `
str += list.map(el => `'${el.name}, ${el.id}번'`).join(", ")
return str
},
}

class Todos {
async add(name, tag) {
if (validator.checkTagShape(tag)) {
throw Error("TAG_SHAPE_ERROR")
}
const todo = {
id: todoUtils.generateId(),
name,
status: "todo",
tag: tag.replace(/\[|\]|\"|\'|\s/g, "").split(",")
}
let message = `${todo.name} 1개가 추가됐습니다.(id : ${todo.id})`
historyQueue.recordTodo(message)
todoList.push(todo)
console.log(message)
await todoUtils.sleep(1000)
this.show("all")
}

async delete(id) {
let index = validator.isExisted(todoList, Number(id))
if (index === -1) throw Error("NOT_EXIST_ID")
let {
name,
status
} = todoList[index]
let message = `${name} ${status}가 목록에서 삭제됐습니다`
historyQueue.recordTodo(message)
todoList.splice(index, 1)
console.log(message)
await todoUtils.sleep(1000)
this.show("all")
}

async update(id, status) {
let index = validator.isExisted(todoList, Number(id))
if (index === -1) throw Error("NOT_EXIST_ID")

else if (!validator.isCorrectStatus(status)) throw Error("INCORRECT_STATUS")
else if (validator.isSameStatus(todoList[index], status)) throw Error("SAME_STATUS")

historyQueue.recordTodo()
todoList[index].status = status
let message = `${todoList[index].name}가 ${todoList[index].status}으로 상태가 변경됐습니다`
await todoUtils.sleep(3000)
console.log(message)
await todoUtils.sleep(1000)
this.show("all")
}

async show(status) {
const option = {
"all": "getAllStr",
"todo": "getStatusStr",
"doing": "getStatusStr",
"done": "getStatusStr"
}
console.log(todoUtils[option[status]](status))
}

undo() {
const {todoList: list} = historyQueue.undo();
todoList.length = 0
JSON.parse(JSON.stringify([...list])).forEach(el => {
todoList.push(el)
})
}

redo() {
const {todoList: list} = historyQueue.redo()
todoList.length = 0
JSON.parse(JSON.stringify([...list])).forEach(el => {
todoList.push(el)
})
}
}

//? history record 할떄 status가 참조하는것 같음

module.exports = Todos
50 changes: 50 additions & 0 deletions oop/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const readline = require("readline")
const Todos = require("./Todos.js")
const validator = require("./validator.js")
const ERR_MSG = require("./ErrorConstant").ERR_MSG
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})

const todos = new Todos()

const getCommand = (command) => {
if (!(command === "undo" || command === "redo") && !validator.isContained(command, "$")) {
throw Error("NO_SHELL")
}
const [inst, ...rest] = command.split("$")
if (!validator.isCorrectCommand(inst)) {
throw Error("INCORRECT_INST")
}
return [inst, rest]
}

rl.setPrompt("명령어를 입력하세요 : ")
rl.prompt()

rl.on("line", async (command) => {
if (command === "quit") {
rl.close()
} else {
try {
[inst, params] = getCommand(command.trim())
const paramErrorFlag = params.some((el) => {
return el === undefined && el === null && !el
})
if ((todos[inst].length !== params.length) || paramErrorFlag) {
throw Error("PARAMETER_ERROR")
}

await todos[inst](...params)
} catch (e) {
console.log('\x1b[31m%s\x1b[0m', "Error : " + ERR_MSG[e.message])
}

rl.prompt()


}
}).on("close", () => {
process.exit()
})
34 changes: 34 additions & 0 deletions oop/validator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const regexObj = {
status : /^done$|^doing$|^todo$/,
command: /^add$|^delete$|^show$|^update$|^undo$|^redo$/,
tag: /(^\[(("[a-z0-9]+")|('[a-z0-9]+'))\]$)|(^\[((("[a-z0-9]+")|('[a-z0-9]+')),\s*)+(("[a-z0-9]+")|('[a-z0-9]+'))\]$)/i
}

const validator = {
isContained: (string, key) => {
return string.includes(key)
},
isExisted: (arr, id) => {
if (!Number.isFinite(id) || arr.length === 0) return -1;
return arr.findIndex((el) => el.id === id)
},
isSameStatus: (obj, status) => {
return obj["status"] === status
},
isCorrectStatus: (status) => {
return regexObj.status.test(status)
},
isCorrectCommand: (inst) => {
return regexObj.command.test(inst)
},
checkTagShape: (tag) => {
let result = regexObj.tag.test(tag)
console.log(tag)
console.log(result)
console.log(!result)
return !result
}
}


module.exports = validator