我们通过写一个基于node的todo-list任务清单,基本就能了解node的文件模块。
cli.js入口文件
需要引入commander(文档)
npm install commander
#!/usr/bin/env node
// 上述注释为了指定用node作为脚本的解释程序——称为shebang
const program = require('commander')
const api = require('./index.js')
const pkg = require('./package.json')
program
.version(pkg.version)
program
.command('add')
.description('add a task')
.action((args) => {
const words = args.args.join(' ')
api.add(words).then(()=> {
console.log('添加成功')
}, ()=> {
console.log('添加失败')
})
})
program
.command('clear')
.description('clear all tasks')
.action((args) => {
api.clear().then(()=> {
console.log('清除完毕')
}), ()=> {
console.log('清除失败')
}
})
program
.command('list')
.description('look all tasks')
.action(() => {
api.showAll()
})
program.parse(process.argv);
index.js 封装相关操作的文件
这里的命令行交互操作使用了inquirer(文档)库来实现的
npm install inquirer
const db = require('./db')
const inquirer = require('inquirer')
module.exports.add = async (title) => {
// 读取之前任务
const list = await db.read()
// 往里面添加一个 title 任务
list.push({title, done: false})
// 存储到任务文件
await db.write(list)
}
module.exports.clear = async () => {
await db.write([])
}
function markAsDone(list, index) {
list[index].done = true
db.write(list)
}
function markAsundone(list, index) {
list[index].done = false
db.write(list)
}
function updateTitle(list, index) {
inquirer.prompt({
type: 'input',
name: 'title',
message: '新的标题',
default: list[index].title
}).then(answer => {
list[index].title = answer.title
db.write(list)
})
}
function remove(list, index) {
list.splice(index, 1)
db.write(list)
}
function askForAction (list, index) {
const actions = {markAsundone, markAsDone, remove, updateTitle}
inquirer.prompt({
type: 'list', name: 'action',
message: '请选择操作',
choices: [
{name: '退出', value: 'quit'},
{name: '已完成', value: 'markAsDone'},
{name: '未完成', value: 'markAsundone'},
{name: '改标题', value: 'updateTitle'},
{name: '删除', value: 'remove'},
]
}).then(answer2 => {
const action = actions[answer2.action]
action && action(list, index)
})
}
function askForCreateTask(list) {
inquirer.prompt({
type: 'input',
name: 'title',
message: '输入任务标题',
}).then(answer => {
list.push({
title: answer.title,
done: false
})
db.write(list)
})
}
function printTasks(list) {
inquirer.prompt({
type: 'list',
name: 'index',
message: '请选择你想操作的任务',
choices: [
{name: '退出', value: '-1'},
...list.map((task, index) => {
return {name: `${task.done ? `[x]` : '[_]'} ${index + 1} - ${task.title}`, value: index.toString()}
}), {name: '+ 创建任务', value: '-2'}]
}).then(anser => {
const index = parseInt(anser.index)
if (index > 0) {
askForAction(list, index)
} else if (index === -2) {
askForCreateTask(list)
}
})
}
module.exports.showAll = async () => {
// 读取之前的任务
const list = await db.read()
// 打印之前的任务
// printTasks
printTasks(list)
}
db.js 文件的读写封装
这里用到了node.js中的fs文件系统(文档)相关api的知识
const homedir = require('os').homedir()
const home = process.env.HOME || homedir
const p = require('path')
const fs = require('fs')
const dbPath = p.join(home, '.todo')
const db = {
read(path = dbPath) {
return new Promise((resolve, reject) => {
fs.readFile(path, {flag: 'a+'}, (error, data) => {
if (error) return reject(error)
let list
try {
list = JSON.parse(data.toString())
} catch (error2) {
list = []
}
resolve(list)
})
})
},
write(list, path = dbPath) {
return new Promise((resolve, reject) => {
const string = JSON.stringify(list)
fs.writeFile(path, string + '\n', (error) => {
if (error) return reject(error)
resolve()
})
})
}
}
module.exports = db
最后就可以在命令行中使用相关命令:
node cli add 'xxxx' // add task
node cli lsit // look all tasks
node cli clear // clear all tasks
另外单个任务的操作可以通过命令行交互实现更多操作。