feat(task): combineEvents
This commit is contained in:
parent
f5a59caca2
commit
60f6e54da1
@ -72,3 +72,43 @@ Task.warning(message, data)
|
|||||||
// - progress
|
// - progress
|
||||||
Task.set(property, value)
|
Task.set(property, value)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `combineEvents`
|
||||||
|
|
||||||
|
Create a consolidated log from individual events.
|
||||||
|
|
||||||
|
It can be used directly as an `onProgress` callback:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { makeOnProgress } from '@vates/task/combineEvents'
|
||||||
|
|
||||||
|
const onProgress = makeOnProgress({
|
||||||
|
// This function is called each time a root task starts.
|
||||||
|
//
|
||||||
|
// It will be called for as many times as there are tasks created with this `onProgress` function.
|
||||||
|
onRootTaskStart(taskLog) {
|
||||||
|
// `taskLog` is an object reflecting the state of this task and all its subtasks,
|
||||||
|
// and will be mutated in real-time to reflect the changes of the task.
|
||||||
|
},
|
||||||
|
|
||||||
|
// This function is called each time a root task ends.
|
||||||
|
onRootTaskEnd(taskLog) {},
|
||||||
|
|
||||||
|
// This function is called each time a root task or a subtask is updated.
|
||||||
|
//
|
||||||
|
// `taskLog.$root` can be used to uncondionally access the root task.
|
||||||
|
onTaskUpdate(taskLog) {},
|
||||||
|
})
|
||||||
|
|
||||||
|
Task.run({ data: { name: 'my task' }, onProgress }, asyncFn)
|
||||||
|
```
|
||||||
|
|
||||||
|
It can also be fed event logs directly:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { makeOnProgress } from '@vates/task/combineEvents'
|
||||||
|
|
||||||
|
const onProgress = makeOnProgress({ onRootTaskStart, onRootTaskEnd, onTaskUpdate })
|
||||||
|
|
||||||
|
eventLogs.forEach(onProgress)
|
||||||
|
```
|
||||||
|
@ -89,6 +89,46 @@ Task.warning(message, data)
|
|||||||
Task.set(property, value)
|
Task.set(property, value)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `combineEvents`
|
||||||
|
|
||||||
|
Create a consolidated log from individual events.
|
||||||
|
|
||||||
|
It can be used directly as an `onProgress` callback:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { makeOnProgress } from '@vates/task/combineEvents'
|
||||||
|
|
||||||
|
const onProgress = makeOnProgress({
|
||||||
|
// This function is called each time a root task starts.
|
||||||
|
//
|
||||||
|
// It will be called for as many times as there are tasks created with this `onProgress` function.
|
||||||
|
onRootTaskStart(taskLog) {
|
||||||
|
// `taskLog` is an object reflecting the state of this task and all its subtasks,
|
||||||
|
// and will be mutated in real-time to reflect the changes of the task.
|
||||||
|
},
|
||||||
|
|
||||||
|
// This function is called each time a root task ends.
|
||||||
|
onRootTaskEnd(taskLog) {},
|
||||||
|
|
||||||
|
// This function is called each time a root task or a subtask is updated.
|
||||||
|
//
|
||||||
|
// `taskLog.$root` can be used to uncondionally access the root task.
|
||||||
|
onTaskUpdate(taskLog) {},
|
||||||
|
})
|
||||||
|
|
||||||
|
Task.run({ data: { name: 'my task' }, onProgress }, asyncFn)
|
||||||
|
```
|
||||||
|
|
||||||
|
It can also be fed event logs directly:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { makeOnProgress } from '@vates/task/combineEvents'
|
||||||
|
|
||||||
|
const onProgress = makeOnProgress({ onRootTaskStart, onRootTaskEnd, onTaskUpdate })
|
||||||
|
|
||||||
|
eventLogs.forEach(onProgress)
|
||||||
|
```
|
||||||
|
|
||||||
## Contributions
|
## Contributions
|
||||||
|
|
||||||
Contributions are _very_ welcomed, either on the documentation or on
|
Contributions are _very_ welcomed, either on the documentation or on
|
||||||
|
77
@vates/task/combineEvents.js
Normal file
77
@vates/task/combineEvents.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const assert = require('node:assert').strict
|
||||||
|
|
||||||
|
const noop = Function.prototype
|
||||||
|
|
||||||
|
function omit(source, keys, target = { __proto__: null }) {
|
||||||
|
for (const key of Object.keys(source)) {
|
||||||
|
if (!keys.has(key)) {
|
||||||
|
target[key] = source[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
const IGNORED_START_PROPS = new Set([
|
||||||
|
'end',
|
||||||
|
'infos',
|
||||||
|
'properties',
|
||||||
|
'result',
|
||||||
|
'status',
|
||||||
|
'tasks',
|
||||||
|
'timestamp',
|
||||||
|
'type',
|
||||||
|
'warnings',
|
||||||
|
])
|
||||||
|
|
||||||
|
exports.makeOnProgress = function ({ onRootTaskEnd = noop, onRootTaskStart = noop, onTaskUpdate = noop }) {
|
||||||
|
const taskLogs = new Map()
|
||||||
|
return function onProgress(event) {
|
||||||
|
const { id, type } = event
|
||||||
|
let taskLog
|
||||||
|
if (type === 'start') {
|
||||||
|
taskLog = omit(event, IGNORED_START_PROPS)
|
||||||
|
taskLog.start = event.timestamp
|
||||||
|
taskLog.status = 'pending'
|
||||||
|
taskLogs.set(id, taskLog)
|
||||||
|
|
||||||
|
const { parentId } = event
|
||||||
|
if (parentId === undefined) {
|
||||||
|
Object.defineProperty(taskLog, '$root', { value: taskLog })
|
||||||
|
|
||||||
|
// start of a root task
|
||||||
|
onRootTaskStart(taskLog)
|
||||||
|
} else {
|
||||||
|
// start of a subtask
|
||||||
|
const parent = taskLogs.get(parentId)
|
||||||
|
assert.notEqual(parent, undefined)
|
||||||
|
|
||||||
|
// inject a (non-enumerable) reference to the parent and the root task
|
||||||
|
Object.defineProperty(taskLog, { $parent: { value: parent }, $root: { value: parent.$root } })
|
||||||
|
;(parent.tasks ?? (parent.tasks = [])).push(taskLog)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
taskLog = taskLogs.get(id)
|
||||||
|
assert.notEqual(taskLog, undefined)
|
||||||
|
|
||||||
|
if (type === 'info' || type === 'warning') {
|
||||||
|
const key = type + 's'
|
||||||
|
const { data, message } = event
|
||||||
|
;(taskLog[key] ?? (taskLog[key] = [])).push({ data, message })
|
||||||
|
} else if (type === 'property') {
|
||||||
|
;(taskLog.properties ?? (taskLog.properties = { __proto__: null }))[event.name] = event.value
|
||||||
|
} else if (type === 'end') {
|
||||||
|
taskLog.end = event.timestamp
|
||||||
|
taskLog.result = event.result
|
||||||
|
taskLog.status = event.status
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'end' && taskLog.$root === taskLog) {
|
||||||
|
onRootTaskEnd(taskLog)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onTaskUpdate(taskLog)
|
||||||
|
}
|
||||||
|
}
|
@ -19,5 +19,9 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"postversion": "npm publish --access public"
|
"postversion": "npm publish --access public"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
".": "./index.js",
|
||||||
|
"./combineEvents": "./combineEvents.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user