Skip to content
Merged
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
31 changes: 23 additions & 8 deletions lib/Journal.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,29 @@ export default class Journal {
*/
constructor ({
logger,
data,
supplementEntry = (entry, data) => entry
data
}) {

/**
* Add supplemental information to the journal
* for both adapt content and plugins
*/
const supplementEntry = (entry, data) => {
switch (entry.keys[0]) {
case 'fromPlugins':
// plugin name
entry._name = data[entry.keys[0]][entry.keys[1]]?.name ?? '';
break;
case 'content':
// object _id, _type and _component or _extension if available
entry._id = data[entry.keys[0]][entry.keys[1]]?._id ?? '';
entry._type = data[entry.keys[0]][entry.keys[1]]?._type ?? '';
if (entry._type && data[entry.keys[0]][entry.keys[1]]?.[`_${entry._type}`]) {
entry._name = entry[`_${entry._type}`] = data[entry.keys[0]][entry.keys[1]]?.[`_${entry._type}`] ?? '';
}
}
return entry;
}
/**
*
* @param {string} method add/set/delete to signify how the JSON was modified
Expand All @@ -82,7 +102,7 @@ export default class Journal {
// Prevent entries from being added whilst undoing.
if (this.isUndoing) return
// Add entries to the entries list with any necessary supplemental information.
this.entries.push(this.supplementEntry({
this.entries.push(supplementEntry({
method,
keys,
// Clone the value and previous to preserve the values of objects by reference.
Expand Down Expand Up @@ -175,11 +195,6 @@ export default class Journal {
}
})
}
/**
* Allows journal entries to contain supplemental information.
* @type {Function}
* */
this.supplementEntry = supplementEntry
/**
* Original JSON.
* @type {Object|Array}
Expand Down
11 changes: 7 additions & 4 deletions lib/Logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import chalk from 'chalk'
import path from 'path'
import fs from 'fs-extra'

function padNum2(value) {
return String(value).padStart(2, '0');
}

export default class Logger {
constructor () {
this.logArr = []
Expand Down Expand Up @@ -40,10 +44,9 @@ export default class Logger {
// Use getDateStamp to return readable date/time string.
static getDateStamp () {
const d = new Date()
const m = d.getMonth() + 1
const date = `${d.getDate()}/${m < 10 ? `0${m}` : m}/${d.getFullYear().toString().slice(2)}`
const time = `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}:${d.getMilliseconds()}`
const str = `${date} - ${time}`
const date = `${d.getFullYear().toString()}/${padNum2(d.getMonth() + 1)}/${padNum2(d.getDate())}`
const time = `${padNum2(d.getHours())}:${padNum2(d.getMinutes())}:${padNum2(d.getSeconds())}.${padNum2(d.getMilliseconds())}`
const str = `${date} ${time}`
return str
}

Expand Down
74 changes: 69 additions & 5 deletions lib/Task.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,74 @@
import globs from 'globs'
import path from 'path'
import fs from 'fs-extra'
import chalk from 'chalk'
import TaskContext from './TaskContext.js'
import Journal from '../lib/Journal.js'
import { exec } from 'child_process'

function makeTable(items, columnNames) {
// calculate the max column widths for the items
const colWidths = items.reduce((colWidths, item) => {
Object.entries(item).forEach(([colName, value]) => {
colWidths[colName] = Math.max(colWidths[colName] ?? 0, value ? String(value).length : 0)
if (!colWidths[colName]) return
// Include column header if data has value
colWidths[colName] = Math.max(colWidths[colName], colName.length)
})
return colWidths
}, {})
// produce a well spaced column names header
const header = columnNames.map(colName => {
if (!colWidths[colName]) return ''
return chalk.cyan(String(colName).padEnd(colWidths[colName] + 1, ' '))
}).join('')
// produce a well spaced data table
const body = items.map(item => {
return columnNames.map(colName => {
if (!colWidths[colName]) return ''
return String(item[colName]).padEnd(colWidths[colName] + 1, ' ')
}).join('')
}).join('\n')
return `${header}\n${body}`
}

function prettyPrintJournal(journal, logger) {
const lines = []
// collect all of the appropriate information about the change
for (const entry of journal.entries) {
const type = (entry.keys[0] === 'fromPlugins')
? 'plugin'
: entry._type
const name = entry._name
const id = entry._id
const action = entry.method
const property = entry.keys.slice(2).join('.')
const value = JSON.stringify(entry.value)
const prev = JSON.stringify(entry.previous)
lines.push({ type, name, id, '#': lines.length, action, property, value, prev })
}
let lineIndex = 0
const output = []
while (lineIndex < lines.length) {
// collect lines with identical subject name values
const fromLineIndex = lineIndex
let toLineIndex = lineIndex
const line = lines[lineIndex]
for (let i = lineIndex; i < lines.length; i++) {
const nextLine = lines[i]
if (nextLine.name !== line.name) break
toLineIndex = i
}
// print a grouped summary of the above lines with a single common subject line
const printLines = lines.slice(fromLineIndex, toLineIndex + 1)
const subjectTable = makeTable([printLines[0]], ['type', 'name', 'id'])
const propertyChangeTable = makeTable(printLines, ['#', 'action','property','value'])
output.push(`${subjectTable}\n${propertyChangeTable}\n`)
lineIndex = toLineIndex + 1
}
logger.info(`Summary of changes:\n\n${output.join('\n')}`)
}

export default class Task {
constructor ({
description = '',
Expand Down Expand Up @@ -259,21 +323,22 @@ export default class Task {
}
logger.debug(`Task -- ${toRun.length} tasks applicable`)
const isExhausted = (!toRun.length)
if (isExhausted) return
if (isExhausted) break
logger.debug('Task -- Running applicable tasks')
// TODO: output task description only on run
const lastJournalEntryIndex = journal.lastEntryIndex
for (const task of toRun) {
const { hasErrored } = await task.run({ cwd, journal, logger })
if (hasErrored) {
journal.undoToIndex(lastJournalEntryIndex)
return
break
}
}
logger.debug('Task -- Applicable tasks finished')
const hasChanged = (lastJournalEntryIndex !== journal.lastEntryIndex)
if (!hasChanged) return
if (!hasChanged) break
}
prettyPrintJournal(journal, logger)
}

static async runTests ({ cwd = process.cwd(), logger }) {
Expand Down Expand Up @@ -309,8 +374,7 @@ export default class Task {
(shouldRun === false && hasRun === false) ||
(shouldStop && hasStopped && !hasErrored)
logger.info(`> ${isPassed ? 'Passed' : 'Failed'}`)
// TODO: make sure journal entries have _id on them so that they're easier to read
// logger.info(journal.entries)
prettyPrintJournal(journal, logger)
}
}
}
Expand Down