Making a TIME Management Tool for the CLI (part 5)

This is the sixth day of my participation in the August More Text Challenge. For details, see “August More Text Challenge”.

preface

The previous article focused on the development of two directives:

  • Initialize the project template directive:timec init <projectName>
  • Initialize the record template instruction:timec create <filename>

This section describes the following: Automatically generates reports within a period of time

The desired directive is: timec-or –range

_

…..

This effect

The function development

Report generation over a period of time

Can be used for weekly, daily, monthly report statistical data generation, to facilitate their own review of the week to do

Instructions to register

Note: The instruction logic that has appeared in previous articles has been omitted

Use the option method to register new optional parameters:

  • -r: Indicates that the report is to be output
  • -r: indicates the range of events to be output
/ / export
commander.arguments('
      
        '
      ) // Multiple files/directories
    .option('-o, --output'.'Export analysis results')
    .option('-r, --report'.'Export the result as a md report')
    .option('-R, --range [startDate_endDate]'.'A time period')
    // .action
Copy the code

Add a simple judgment logic:

  • -rThe corresponding isreportProperties, astrueIndicates that this option is enabled
  • -RThe correspondingrangeProperty whose value isstringtype
    • Start and end times are underlined_segmentation
  • Focus on thegetJSONByRangewithoutPutReportThe implementation of these two methods
  • Content read logic (content), which has been discussed in detail in previous articles, so I won’t repeat it here
    .action((filenames, cmdObj) = > {
        const { output,report } = cmdObj
        / / export
        if (output) {
            let outFileName = 'res'

            if(report){
                const {range} = cmdObj
                if(range){
                    const [startTime,endTime] = range.split('_')
                    // createFile(getFilePath(cwd, `report-${outFileName}.md`),outPutReport(getJSONByRange(content,startTime,endTime)),false)
                    // To facilitate the observation of the call structure, expand as follows
                    const outPutPath = getFilePath(cwd, `report-${outFileName}.md`)
                    const json = getJSONByRange(content,startTime,endTime)
                    const data = outPutReport(json)
                    createFile(outPutPath,data,false)}}}})Copy the code

Json fetch in scope

The logic is relatively simple:

  1. First callgetJSONMethod to turn the incoming content into a JSON object
    • Every single one of themtitleforyyyy-mm-ddThe date of the
  2. First callsortMethods The data were sorted by time from small to large
  3. In the use offilterMethod to filter the data according to the incoming start and end time
  4. In the end, the desired result is produced
function getJSONByRange(fileContent, startTime, endTime) {
    let jsonSchema = getJSON(fileContent)
    // Row from small to large
    jsonSchema = jsonSchema.sort((a, b) = > {
        const d1 = new Date(a.title)
        const d2 = new Date(b.title)
        return d1 - d2
    }).filter(v= > {
        const d = new Date(v.title)
        const s = new Date(startTime)
        const e = new Date(endTime)
        return d >= s && d <= e
    })
    return jsonSchema
}
Copy the code

JSON transfer report content

The format of the expected report content is as follows

# Start time - End time
** Total time ** xxx

# # task name> Time: YYYY*Event 1*Event 2*Event 3# # task name> Time: YYYY*Event 1*Event 2*Event 3Copy the code

With the structure down, let’s start working on the JSON data

The JSON data structure is as follows (just a review)

[{"title": "2021-08-03"."tasks": [{"title": "Task 1"."things": [{"time": "0.2"."content": "A component"
          },
          {
            "time": "0.3"."content": Component "b"}]},]},]Copy the code

First use an array to hold the result of each row of data (each row of final MD)

const res = []

// Record the total time
let sumTime = 0
Copy the code

The start time and end time are the title of the first item and the last item of the JSON object respectively

const startDate = jsonSchema[0].title
const endDate = jsonSchema[jsonSchema.length-1].title
/ / time
res.push(` #${startDate}${endDate}`)
Copy the code

After the time is determined, the task is classified

Use array.prototype. reduce for most operations. If you are not familiar with it, you can query it by MDN

Start by putting all tasks in the same array:

  • I’m going to iterate and I’m going to useconcatLink these arrays
// Filter out all tasks
const allTasks = jsonSchema.reduce((pre,current) = >{
    return pre.concat(current.tasks)
},[])
Copy the code

Merge things with the same task

Before the merger

[{"title": "Task 1"."things": [{"time": "0.2"."content": "A component"]}, {},"title": "Task 1"."things": [{"time": "0.3"."content": Component "b"}}],]Copy the code

After the merger

[{"title": "Task 1"."things": [{"time": "0.2"."content": "A component"
      },
      {
        "time": "0.3"."content": Component "b"}}]]Copy the code

With the structure determined, the logical code is easy to write:

  • ifpreAn empty array is stored directly
  • Iterate over what has been saved to see if the same tasks exist
    • If no, joinpre
    • If it exists, its things are addedpre.things
// Merge the same tasks
const tasks = allTasks.reduce((pre,current) = >{
    if(pre.length===0){
        pre.push(current)
        return pre
    }
    let sameTask = pre.find(v= >v.title===current.title)
    if(! sameTask){ pre.push(current)returnpre } sameTask.things.push(... current.things)return pre
},[])
Copy the code

With the structure sorted out, it’s time to generate the content:

  • usefor... ofIterate over each task
  • Internal useArray.prototype.mapTraverse the transaction
    • The task time is calculated while traversing
  • After a task is traversed, add the task time first and then add the transaction list
  • Finally, the total time used by all tasks is utilized by the arrayspliceMethod to insert into the second item of the result

At this point, the logic to generate the scope report is complete

for (const taskItem of tasks) {
    res.push(' ')
    res.push(` # #${taskItem.title}`)
    let taskTime = 0
    let things = taskItem.things.map(thing= >{
        const {time,content} = thing
        taskTime += (+time)
        return ` *${content}`
    })
    res.push(` > time:${taskTime.toFixed(2)}`) res.push(... things) sumTime += taskTime } res.splice(1.0.'** Total time **${sumTime.toFixed(2)}`)
Copy the code

The complete code address for this section

other

Because of the limited free time each day, this article will stop there

If you still feel more than enough, please stay tuned for further updates, or check out the warehouse first

Welcome to comment section to raise demand, exchange discussion

This series will continue to be updated and iterated until the first generation of the product is completed

  • The warehouse address