粥里有勺糖

vuePress-theme-reco 粥里有勺糖    2018 - 2023
粥里有勺糖 粥里有勺糖

Choose mode

  • dark
  • auto
  • light
关于我
备战春秋
  • 心得总结
  • 校招考点汇总
  • 面经汇总
  • 复习自查
技术笔记
  • 技术教程
  • 模板工程
  • 源码学习
  • 技术概念
  • 个人作品
  • 学习笔记
计算机基础
  • 算法与数据结构
  • 操作系统
  • 计算机网络
  • 设计模式
  • 剑指offer
大前端
  • javascript
  • vue
  • html
  • css
  • 🌏浏览器专题
  • Web性能优化
  • regexp
  • node
面试
  • 问解
  • javascript
  • css
  • 手撕代码
  • 性能优化
  • 综合问题
  • 面经汇总
  • 小程序
手撕代码
  • 数据结构与算法
  • javascript
  • css
个人站点
  • GitHub (opens new window)
  • 博客园 (opens new window)
  • 掘金 (opens new window)
线上作品
  • 轻取(文件收集) (opens new window)
  • 个人图床 (opens new window)
  • 考勤小程序 (opens new window)
  • 时光恋人 (opens new window)
  • 在线简历生成 (opens new window)
留言板
Github (opens new window)
author-avatar

粥里有勺糖

285

文章

40

标签

关于我
备战春秋
  • 心得总结
  • 校招考点汇总
  • 面经汇总
  • 复习自查
技术笔记
  • 技术教程
  • 模板工程
  • 源码学习
  • 技术概念
  • 个人作品
  • 学习笔记
计算机基础
  • 算法与数据结构
  • 操作系统
  • 计算机网络
  • 设计模式
  • 剑指offer
大前端
  • javascript
  • vue
  • html
  • css
  • 🌏浏览器专题
  • Web性能优化
  • regexp
  • node
面试
  • 问解
  • javascript
  • css
  • 手撕代码
  • 性能优化
  • 综合问题
  • 面经汇总
  • 小程序
手撕代码
  • 数据结构与算法
  • javascript
  • css
个人站点
  • GitHub (opens new window)
  • 博客园 (opens new window)
  • 掘金 (opens new window)
线上作品
  • 轻取(文件收集) (opens new window)
  • 个人图床 (opens new window)
  • 考勤小程序 (opens new window)
  • 时光恋人 (opens new window)
  • 在线简历生成 (opens new window)
留言板
Github (opens new window)
  • wheel

    • 个人作品
    • 时间管理CLI工具
      • 做一个CLI版的时间管理工具(一)
      • 做一个CLI版的时间管理工具(十)
      • 做一个CLI版的时间管理工具(11)
      • 做一个CLI版的时间管理工具(12)
      • 做一个CLI版的时间管理工具(13)
      • 做一个CLI版的时间管理工具(14)
      • 做一个CLI版的时间管理工具(15)
      • 做一个CLI版的时间管理工具(二)
      • 做一个CLI版的时间管理工具(三)
      • 做一个CLI版的时间管理工具(四)
      • 做一个CLI版的时间管理工具(五)
      • 做一个CLI版的时间管理工具(六)
      • 做一个CLI版的时间管理工具(七)
      • 做一个CLI版的时间管理工具(八)
      • 做一个CLI版的时间管理工具(九)
    • 组装个支持记笔记的CodePen
    • ESCheck工具原理解析及增强实现
    • 一款检测代码中TODO的eslint插件
    • 实现一个Web UI检测(视觉走查)工具ing
    • 从0-1实现文件下载CLI工具
    • 内联JS处理(ES语法降级&内容压缩)
    • Node CLI工具原理解析
    • 我打造的在线简历生成应用
    • 助你轻松编写与分享snippet的VsCode插件
    • SourceMap解析CLI工具实现
    • 一个通过NPM包共(分)享代码块的解决方案
    • 实践:给女朋友个性化定制应用-体重记录(一)
    • 实践:给女朋友个性化定制应用-体重记录(二)
    • 实践:给女朋友个性化定制应用-体重记录(三)

做一个CL版的时间管理工具(三)

vuePress-theme-reco 粥里有勺糖    2018 - 2023

做一个CL版的时间管理工具(三)

粥里有勺糖 2021-08-04 技术笔记个人作品CLI工具

# 做一个CLI版的时间管理工具(三)

# 前言

上一篇文章完成了markdown转JSON的逻辑与 自定义指令的添加介绍

本文将详细讲解一些 从输入指令timec -oj filepath1 filepath2 .... 到正确执行的逻辑

# 功能开发

# 批量MD转JSON详细逻辑

将传入的相对路径转绝对路径

  • 其中process.cwd()标识命令的执行目录
const path = require('path')
// 首先获得命令执行目录
const cwd = process.cwd()

// 将传入的相对文件路径批量转为绝对路径
filenames = filenames.map(f=>{
  return path.join(cwd,f)
})
1
2
3
4
5
6
7
8

批量获取多个文件的内容:

  • 使用fs.readFileSync获取单个文件的内容
  • 利用Array.prototype.reduce合并多个文件的内容,以\n分割
const fs = require('fs')

/**
 * 获取文件内容
 * @param {string} filepath 
 */
function getFileContent(filepath) {
    return fs.readFileSync(filepath, { encoding: 'utf-8' })
}
/**
 * 获取多个文件的内容
 * @param {string[]} files 
 */
function getFilesContent(files) {
    return files.reduce((pre, now) => {
        pre += '\n'
        pre += getFileContent(now)
        return pre
    }, '')
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

将MD转为JSON并输出到文件:

  • 转为JSON的详细逻辑看上一篇文章的介绍
  • 创建文件时需判断原文件是否已存在,存在则使用新的名称,避免覆盖内容
// 获取所有文件的内容
const content = getFilesContent(filenames)

let outFileName = 'res'
// 转为JSON对象,并执行JSON.stringify
createFile(path.join(cwd, `${outFileName}.json`), outputJson(content), false)

// ------------------------------------------------
function outputJson(content) {
    return JSON.stringify(getJSON(content))
}

/**
 * 创建一个新文件
 * @param {string} path 
 * @param {string} content 
 * @param {boolean} judgeRepeat
 */
function createFile(path, content, judgeRepeat = true) {
    if (!fs.existsSync(path)) {
        fs.writeFileSync(path, content, { encoding: 'utf-8' })
        return true
    }
    if (judgeRepeat) {
        console.error(`${path} 已存在`);
        return false
    }
    fs.writeFileSync(getNoRepeatFilePath(path), content, { encoding: 'utf-8' })
    return true
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

根据已存在的路径,生成一个新的路径逻辑如下

  • 往文件名末尾添加一个自增的数字
    • 通过path.parse方法解析路径 (/user/home/abc.txt)
      • dir:目录 (/user/home)
      • name:文件名 (abc)
      • ext:文件后缀 (.txt)
  • 如果数字存在则自增这个数字,直至数字不存在
/**
 * 获取与原文件不重复的一个文件路经
 * @param {string} originPath 
 */
function getNoRepeatFilePath(originPath) {
    let num = 1
    const { dir, name, ext } = path.parse(originPath)
    if (!fs.existsSync(originPath)) {
        return originPath
    }
    while (fs.existsSync(getFilePath(dir, `${name}-${num}${ext}`))) {
        num += 1
    }
    return getFilePath(dir, `${name}-${num}${ext}`)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

到此从 MD读取 -> 转换为JSON -> 写出到文件 流程都拆解阐述完毕

# 合并MD记录并按时间排序

咱们再给它添加一个--markdownoptions用与后续的合并多个markdown逻辑

commander.arguments('<filenames...>') // 多个文件/目录
    .option('-m, --markdown', 'Export the result as a markdown file')
    .action((filenames, cmdObj) => {
        const { output,markdown } = cmdObj

        // 导出
        if (output) {
            let outFileName = 'res'
            // 获取所有文件的内容(同上)
            const content = getFilesContent(filenames.map(filename => {
                return getFilePath(cwd, filename)
            }))
            if (markdown) {
                createFile(getFilePath(cwd, `${outFileName}.md`), outPutMarkdown(getJSON(content),time), false)
            }
        }
    })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

代码涉及到的其它函前面些文章已经做了详细介绍

下面围绕outPutMarkdown逻辑展开:

  • 先获取所有md文件的内容,再调用getJSON方法转为JSON对象
  • 调用sort方法对title(时间)进行排序
  • 将排序后的json对象,调用getEverydayData详细转换每一天的数据
function outPutMarkdown(jsonSchema,withTime = false) {
    // 从小到大排
    jsonSchema = jsonSchema.sort((a, b) => {
        const d1 = new Date(a.title)
        const d2 = new Date(b.title)
        return d1 - d2
    })
    const res = []
    res.push(...getEverydayData(jsonSchema, withTime))
    return res.join('\n')
}
1
2
3
4
5
6
7
8
9
10
11

遍历每一天的数据,利用reduce嵌套配合unshift方法

从每一个具体事件(以 * 开头)开始遍历,解析事件的内容和消耗时间,然后累加得出任务耗时与每一天的耗时

function getEverydayData(timeDesc, withTime = false) {
    let res = []
    // 按天任务时间汇总
    timeDesc.forEach(oneDay => {
        const _oneRes = []
        const { title, tasks } = oneDay
        const sum = tasks.reduce((pre, task, _i) => {
            const { title, things } = task
            const sum = things.reduce((pre, thing) => {
                // 某件事情况
                const { content, time } = thing
                _oneRes.unshift(`* ${content} -- ${fixedNum(time)}`)
                return pre + (+thing.time)
            }, 0)

            // 某一个任务
            _oneRes.unshift(`## ${title} -- ${fixedNum(sum)}`)
            return pre + sum
        }, 0)

        // 一天的标题
        _oneRes.unshift(`# ${title} -- ${fixedNum(sum)}`)
        res.push(..._oneRes, '')
    })
    // 去掉统计的时间
    if (!withTime) {
        res = res.map(v => {
            return v.replace(/\s--.*/, '')
        })
    }
    return res
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 指令效果

图片

# 其它

下一期根据已有的功能整个周报生成

由于每天空闲时间有限,本文就先到这

如果读者还感觉意犹未尽,敬请期待后续更新,或先关注一下仓库 (opens new window)

欢迎评论区提需求,交流探讨

本系列会不断的更新迭代,直至产品初代完成

  • 仓库地址 (opens new window)
Edit this page (opens new window)
Last Updated: 2022/5/15 12:46:34