taskgroup
Advanced tools
Comparing version 2.0.0 to 3.0.0
// Generated by CoffeeScript 1.6.2 | ||
var TaskGroup, ambi, typeChecker, | ||
var EventEmitter, Task, TaskGroup, ambi, | ||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, | ||
__hasProp = {}.hasOwnProperty, | ||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, | ||
__slice = [].slice; | ||
typeChecker = require('typechecker'); | ||
ambi = require('ambi'); | ||
TaskGroup = (function() { | ||
_Class.prototype.total = 0; | ||
EventEmitter = require('eventemitter2').EventEmitter2; | ||
_Class.prototype.completed = 0; | ||
Task = (function(_super) { | ||
__extends(Task, _super); | ||
_Class.prototype.running = 0; | ||
Task.prototype.type = 'task'; | ||
_Class.prototype.exited = false; | ||
Task.prototype.completed = false; | ||
_Class.prototype.breakOnError = true; | ||
Task.prototype.parent = null; | ||
_Class.prototype.autoClear = false; | ||
Task.prototype.name = null; | ||
_Class.prototype.queue = []; | ||
Task.prototype.fn = null; | ||
_Class.prototype.mode = 'parallel'; | ||
function Task() { | ||
var args, fn, name; | ||
_Class.prototype.lastResult = null; | ||
_Class.prototype.results = []; | ||
_Class.prototype.errors = []; | ||
_Class.prototype.next = function() { | ||
throw new Error('Groups require a completion callback'); | ||
}; | ||
function _Class() { | ||
var arg, args, autoClear, breakOnError, mode, next, _i, _len; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
this.clear(); | ||
for (_i = 0, _len = args.length; _i < _len; _i++) { | ||
arg = args[_i]; | ||
if (typeChecker.isString(arg)) { | ||
if (arg === 'serial' || arg === 'sync') { | ||
this.mode = 'serial'; | ||
} | ||
} else if (typeChecker.isFunction(arg)) { | ||
this.next = arg; | ||
} else if (typeChecker.isObject(arg)) { | ||
next = arg.next, mode = arg.mode, breakOnError = arg.breakOnError, autoClear = arg.autoClear; | ||
if (next) { | ||
this.next = next; | ||
} | ||
if (mode) { | ||
this.mode = mode; | ||
} | ||
if (breakOnError) { | ||
this.breakOnError = breakOnError; | ||
} | ||
if (autoClear) { | ||
this.autoClear = autoClear; | ||
} | ||
} else { | ||
throw new Error('Unknown argument sent to Groups constructor'); | ||
this.setConfig = __bind(this.setConfig, this); | ||
Task.__super__.constructor.apply(this, arguments); | ||
name = fn = null; | ||
if (args.length) { | ||
if (args.length === 2) { | ||
name = args[0], fn = args[1]; | ||
} else if (args.length === 1) { | ||
fn = args[0]; | ||
} | ||
} | ||
this.setConfig({ | ||
name: name, | ||
fn: fn | ||
}); | ||
this; | ||
} | ||
_Class.prototype.clear = function() { | ||
this.total = 0; | ||
this.completed = 0; | ||
this.running = 0; | ||
this.exited = false; | ||
this.queue = []; | ||
this.results = []; | ||
this.errors = []; | ||
this.lastResult = null; | ||
Task.prototype.setConfig = function(opts) { | ||
var key, value; | ||
if (opts == null) { | ||
opts = {}; | ||
} | ||
for (key in opts) { | ||
if (!__hasProp.call(opts, key)) continue; | ||
value = opts[key]; | ||
this[key] = value; | ||
} | ||
return this; | ||
}; | ||
_Class.prototype.hasTasks = function() { | ||
return this.queue.length !== 0; | ||
}; | ||
Task.prototype.run = function() { | ||
var complete, | ||
_this = this; | ||
_Class.prototype.hasCompleted = function() { | ||
return this.total !== 0 && this.total === this.completed; | ||
}; | ||
complete = function() { | ||
var args; | ||
_Class.prototype.isRunning = function() { | ||
return this.running !== 0; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
_this.completed = true; | ||
return _this.emit.apply(_this, ['complete'].concat(__slice.call(args))); | ||
}; | ||
this.emit('run'); | ||
process.nextTick(function() { | ||
return ambi(_this.fn.bind(_this), complete); | ||
}); | ||
return this; | ||
}; | ||
_Class.prototype.hasExited = function(value) { | ||
if (value != null) { | ||
this.exited = value; | ||
} | ||
return this.exited === true; | ||
}; | ||
return Task; | ||
_Class.prototype.logError = function(err) { | ||
if (this.errors[this.errors.length - 1] !== err) { | ||
this.errors.push(err); | ||
} | ||
return this; | ||
}; | ||
})(EventEmitter); | ||
_Class.prototype.complete = function() { | ||
var args, err; | ||
TaskGroup = (function(_super) { | ||
__extends(TaskGroup, _super); | ||
TaskGroup.prototype.type = 'taskgroup'; | ||
TaskGroup.prototype.running = 0; | ||
TaskGroup.prototype.remaining = null; | ||
TaskGroup.prototype.err = null; | ||
TaskGroup.prototype.results = null; | ||
TaskGroup.prototype.parent = null; | ||
TaskGroup.prototype.paused = true; | ||
TaskGroup.prototype.name = null; | ||
TaskGroup.prototype.fn = null; | ||
TaskGroup.prototype.concurrency = 1; | ||
TaskGroup.prototype.pauseOnError = true; | ||
function TaskGroup() { | ||
var args, fn, name, | ||
_this = this; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
err = args[0] || void 0; | ||
this.lastResult = args; | ||
if (err) { | ||
this.logError(err); | ||
this.run = __bind(this.run, this); | ||
this.pause = __bind(this.pause, this); | ||
this.stop = __bind(this.stop, this); | ||
this.clear = __bind(this.clear, this); | ||
this.complete = __bind(this.complete, this); | ||
this.nextItem = __bind(this.nextItem, this); | ||
this.nextItems = __bind(this.nextItems, this); | ||
this.isReady = __bind(this.isReady, this); | ||
this.hasItems = __bind(this.hasItems, this); | ||
this.addGroup = __bind(this.addGroup, this); | ||
this.createGroup = __bind(this.createGroup, this); | ||
this.addTask = __bind(this.addTask, this); | ||
this.createTask = __bind(this.createTask, this); | ||
this.addItem = __bind(this.addItem, this); | ||
this.setConfig = __bind(this.setConfig, this); | ||
TaskGroup.__super__.constructor.apply(this, arguments); | ||
this.err = null; | ||
this.results = []; | ||
this.remaining = []; | ||
name = fn = null; | ||
if (args.length) { | ||
if (args.length === 2) { | ||
name = args[0], fn = args[1]; | ||
} else if (args.length === 1) { | ||
fn = args[0]; | ||
} | ||
} | ||
this.results.push(args); | ||
if (this.running !== 0) { | ||
--this.running; | ||
} | ||
if (this.hasExited()) { | ||
this.setConfig({ | ||
name: name, | ||
fn: fn | ||
}); | ||
this.on('run', function() { | ||
var _ref; | ||
} else { | ||
if (err && this.breakOnError) { | ||
this.exit(); | ||
} else { | ||
++this.completed; | ||
if (this.hasTasks()) { | ||
this.nextTask(); | ||
} else if (this.isRunning() === false && this.hasCompleted()) { | ||
this.exit(); | ||
} | ||
return (_ref = _this.fn) != null ? _ref.call(_this, _this.addGroup, _this.addTask) : void 0; | ||
}); | ||
process.nextTick(function() { | ||
if (_this.fn && !_this.parent) { | ||
return _this.run(); | ||
} | ||
}); | ||
this.on('item.complete', function() { | ||
var args; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
_this.results.push(args); | ||
if (args[0]) { | ||
_this.err = args[0]; | ||
} | ||
--_this.running; | ||
if (_this.paused) { | ||
return; | ||
} | ||
if (!_this.complete()) { | ||
return _this.nextItems(); | ||
} | ||
}); | ||
this; | ||
} | ||
TaskGroup.prototype.setConfig = function(opts) { | ||
var key, value; | ||
if (opts == null) { | ||
opts = {}; | ||
} | ||
for (key in opts) { | ||
if (!__hasProp.call(opts, key)) continue; | ||
value = opts[key]; | ||
this[key] = value; | ||
} | ||
return this; | ||
}; | ||
_Class.prototype.completer = function() { | ||
var _this = this; | ||
TaskGroup.prototype.addItem = function(item) { | ||
var me; | ||
return function() { | ||
me = this; | ||
item.onAny(function() { | ||
var args; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
return _this.complete.apply(_this, args); | ||
}; | ||
return me.emit.apply(me, ["item." + this.event].concat(__slice.call(args))); | ||
}); | ||
this.emit('add', item); | ||
this.remaining.push(item); | ||
if (!this.paused) { | ||
this.nextItems(); | ||
} | ||
return item; | ||
}; | ||
_Class.prototype.exit = function(err) { | ||
var errors, lastResult, results; | ||
TaskGroup.prototype.createTask = function() { | ||
var args, task; | ||
if (err == null) { | ||
err = null; | ||
} | ||
if (err) { | ||
this.logError(err); | ||
} | ||
if (this.hasExited()) { | ||
} else { | ||
lastResult = this.lastResult; | ||
results = this.results; | ||
if (this.errors.length === 0) { | ||
errors = null; | ||
} else if (this.errors.length === 1) { | ||
errors = this.errors[0]; | ||
} else { | ||
errors = this.errors; | ||
} | ||
if (this.autoClear) { | ||
this.clear(); | ||
} else { | ||
this.hasExited(true); | ||
} | ||
this.next(errors, lastResult, results); | ||
} | ||
return this; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
task = (function(func, args, ctor) { | ||
ctor.prototype = func.prototype; | ||
var child = new ctor, result = func.apply(child, args); | ||
return Object(result) === result ? result : child; | ||
})(Task, args, function(){}); | ||
return task; | ||
}; | ||
_Class.prototype.tasks = function(tasks) { | ||
var task, _i, _len; | ||
TaskGroup.prototype.addTask = function() { | ||
var args, me, task; | ||
for (_i = 0, _len = tasks.length; _i < _len; _i++) { | ||
task = tasks[_i]; | ||
this.push(task); | ||
} | ||
return this; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
me = this; | ||
task = this.createTask.apply(this, args).setConfig({ | ||
parent: this | ||
}); | ||
task.onAny(function() { | ||
var args; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
return me.emit.apply(me, ["task." + this.event].concat(__slice.call(args))); | ||
}); | ||
return this.addItem(task); | ||
}; | ||
_Class.prototype.push = function() { | ||
var args; | ||
TaskGroup.prototype.createGroup = function() { | ||
var args, group; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
++this.total; | ||
this.queue.push(args); | ||
return this; | ||
group = (function(func, args, ctor) { | ||
ctor.prototype = func.prototype; | ||
var child = new ctor, result = func.apply(child, args); | ||
return Object(result) === result ? result : child; | ||
})(TaskGroup, args, function(){}); | ||
return group; | ||
}; | ||
_Class.prototype.pushAndRun = function() { | ||
var args; | ||
TaskGroup.prototype.addGroup = function() { | ||
var args, group, me; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
if (this.mode === 'serial' && this.isRunning()) { | ||
this.push.apply(this, args); | ||
} else { | ||
++this.total; | ||
this.runTask(args); | ||
} | ||
return this; | ||
me = this; | ||
group = this.createGroup.apply(this, args).setConfig({ | ||
concurrency: this.concurrency, | ||
parent: this | ||
}); | ||
group.onAny(function() { | ||
var args; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
return me.emit.apply(me, ["group." + this.event].concat(__slice.call(args))); | ||
}); | ||
return this.addItem(group); | ||
}; | ||
_Class.prototype.nextTask = function() { | ||
var task; | ||
TaskGroup.prototype.hasItems = function() { | ||
return this.remaining.length !== 0; | ||
}; | ||
if (this.hasTasks()) { | ||
task = this.queue.shift(); | ||
this.runTask(task); | ||
} | ||
return this; | ||
TaskGroup.prototype.isReady = function() { | ||
return !this.concurrency || this.running < this.concurrency; | ||
}; | ||
_Class.prototype.runTask = function(task) { | ||
var err, me, run; | ||
TaskGroup.prototype.nextItems = function() { | ||
var item, items; | ||
me = this; | ||
try { | ||
run = function() { | ||
var complete, _task; | ||
++me.running; | ||
complete = me.completer(); | ||
if (typeChecker.isArray(task)) { | ||
if (task.length === 2) { | ||
_task = task[1].bind(task[0]); | ||
} else if (task.length === 1) { | ||
_task = task[0]; | ||
} else { | ||
throw new Error('an invalid task was pushed'); | ||
} | ||
} else { | ||
_task = task; | ||
} | ||
return ambi(_task, complete); | ||
}; | ||
if (this.completed !== 0 && (this.mode === 'parallel' || (this.completed % 100) === 0)) { | ||
setTimeout(run, 0); | ||
items = []; | ||
while (true) { | ||
item = this.nextItem(); | ||
if (item) { | ||
items.push(item); | ||
} else { | ||
run(); | ||
break; | ||
} | ||
} catch (_error) { | ||
err = _error; | ||
this.complete(err); | ||
} | ||
return this; | ||
if (items.length) { | ||
return items; | ||
} else { | ||
return false; | ||
} | ||
}; | ||
_Class.prototype.run = function(mode) { | ||
var task, _i, _len, _ref, _ref1; | ||
TaskGroup.prototype.nextItem = function() { | ||
var nextItem; | ||
if (this.isRunning() === false) { | ||
if (mode) { | ||
this.mode = mode; | ||
if (this.hasItems()) { | ||
if (this.isReady()) { | ||
nextItem = this.remaining.shift(); | ||
++this.running; | ||
nextItem.run(); | ||
return nextItem; | ||
} | ||
this.hasExited(false); | ||
if (this.hasTasks()) { | ||
if ((_ref = this.mode) === 'serial' || _ref === 'sync') { | ||
this.nextTask(); | ||
} else { | ||
_ref1 = this.queue; | ||
for (_i = 0, _len = _ref1.length; _i < _len; _i++) { | ||
task = _ref1[_i]; | ||
this.nextTask(); | ||
} | ||
} | ||
} else { | ||
this.exit(); | ||
} | ||
return false; | ||
}; | ||
TaskGroup.prototype.complete = function() { | ||
var completed, empty, pause; | ||
pause = this.pauseOnError && this.err; | ||
empty = this.hasItems() === false && this.running === 0; | ||
completed = pause || empty; | ||
if (completed) { | ||
if (pause) { | ||
this.pause(); | ||
} | ||
this.emit('complete', this.err, this.results); | ||
this.err = null; | ||
this.results = []; | ||
} | ||
return this; | ||
return completed; | ||
}; | ||
_Class.prototype.async = function() { | ||
return this.parallel(); | ||
TaskGroup.prototype.clear = function() { | ||
this.remaining.splice(0); | ||
return this; | ||
}; | ||
_Class.prototype.parallel = function() { | ||
this.run('parallel'); | ||
TaskGroup.prototype.stop = function() { | ||
this.pause(); | ||
this.clear(); | ||
return this; | ||
}; | ||
_Class.prototype.sync = function() { | ||
return this.serial(); | ||
TaskGroup.prototype.pause = function() { | ||
this.paused = true; | ||
return this; | ||
}; | ||
_Class.prototype.serial = function() { | ||
this.run('serial'); | ||
TaskGroup.prototype.run = function() { | ||
var args, | ||
_this = this; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
this.paused = false; | ||
this.emit('run'); | ||
process.nextTick(function() { | ||
if (!_this.complete()) { | ||
return _this.nextItems(); | ||
} | ||
}); | ||
return this; | ||
}; | ||
return _Class; | ||
return TaskGroup; | ||
})(); | ||
})(EventEmitter); | ||
module.exports = TaskGroup; | ||
module.exports = { | ||
Task: Task, | ||
TaskGroup: TaskGroup | ||
}; |
{ | ||
"name": "taskgroup", | ||
"version": "2.0.0", | ||
"description": "Group together synchronous and asynchronous tasks and execute them in either serial or parallel", | ||
"version": "3.0.0", | ||
"description": "Group together synchronous and asynchronous tasks and execute them with support for concurrency, naming, and nesting.", | ||
"homepage": "https://github.com/bevry/taskgroup", | ||
@@ -12,3 +12,4 @@ "keywords": [ | ||
"tasks", | ||
"batch" | ||
"batch", | ||
"concurrency" | ||
], | ||
@@ -33,8 +34,9 @@ "author": "Bevry Pty Ltd <us@bevry.me> (http://bevry.me)", | ||
"dependencies": { | ||
"typechecker": "~2.0.1", | ||
"ambi": "~2.0.0" | ||
"ambi": "~2.0.0", | ||
"eventemitter2": "~0.4.11" | ||
}, | ||
"devDependencies": { | ||
"coffee-script": "~1.6.2", | ||
"joe": "~1.1.2" | ||
"joe": "~1.1.2", | ||
"chai": "~1.5.0" | ||
}, | ||
@@ -45,5 +47,5 @@ "directories": { | ||
"scripts": { | ||
"test": "node ./out/test/taskgroup-test.js --joe-reporter=list" | ||
"test": "node ./out/test/taskgroup-test.js" | ||
}, | ||
"main": "./out/lib/taskgroup.js" | ||
} |
138
README.md
@@ -1,6 +0,10 @@ | ||
# Task Group [![Build Status](https://secure.travis-ci.org/bevry/taskgroup.png?branch=master)](http://travis-ci.org/bevry/taskgroup) | ||
Group together synchronous and asynchronous tasks and execute them in either serial or parallel | ||
# Task Group | ||
[![Build Status](https://secure.travis-ci.org/bevry/taskgroup.png?branch=master)](http://travis-ci.org/bevry/taskgroup) | ||
[![NPM version](https://badge.fury.io/js/taskgroup.png)](https://npmjs.org/package/taskgroup) | ||
Group together synchronous and asynchronous tasks and execute them with support for concurrency, naming, and nesting. | ||
## Install | ||
@@ -21,24 +25,120 @@ | ||
``` coffeescript | ||
# Import | ||
TaskGroup = require('taskgroup') | ||
### Example | ||
# Add tasks to the group and fire them in parallel | ||
tasks = new TaskGroup (err,lastResult,results) -> console.log(err,lastResult,results) | ||
tasks.push (complete) -> | ||
someAsyncFunction(arg1, arg2, complete) | ||
tasks.push -> | ||
someSyncFunction(arg1, arg2) | ||
tasks.run() # can also use tasks.run('parallel') | ||
``` javascript | ||
// Import | ||
var TaskGroup = require('taskgroup').TaskGroup; | ||
# Add tasks to the group and fire them in serial | ||
tasks = new TaskGroup (err,lastResult,results) -> console.log(err,lastResult,results) | ||
tasks.push (complete) -> | ||
someAsyncFunction(arg1, arg2, complete) | ||
tasks.push -> | ||
someSyncFunction(arg1, arg2) | ||
tasks.run('serial') | ||
// Create our new group | ||
var group = new TaskGroup(); | ||
// Define what should happen once the group has completed | ||
group.once('complete', function(err,results){ | ||
// Log the error that has occured | ||
console.log(err); | ||
// => null | ||
// Log the results that our group received from the executing items | ||
console.log(JSON.stringify(results)); | ||
/* => | ||
[ | ||
[null, 'first', 'task'], | ||
[null, 'second task'], | ||
[null, [ | ||
[null, 'sub second task'], | ||
[null, 'sub first', 'task'] | ||
]] | ||
] | ||
*/ | ||
}); | ||
// Add an asynchronous task that gives the result to the completion callback | ||
group.addTask(function(complete){ | ||
setTimeout(function(){ | ||
complete(null, 'first', 'task'); | ||
},500); | ||
}); | ||
// Add a synchronous task that returns the result | ||
// Errors should be returned, though if an error is thrown we will catch it | ||
group.addTask(function(){ | ||
return 'second task'; | ||
}); | ||
// Add a sub-group to our exiting group | ||
group.addGroup(function(addGroup,addTask){ | ||
// Tell this sub-group to execute in parallel (all at once) by setting its concurrency to unlimited | ||
// by default the concurrency for all groups is set to 1 | ||
// which means that they execute in serial fashion (one after the other, instead of all at once) | ||
this.setConfig({concurrency:0}); | ||
// Add an asynchronous task that gives its result to the completion callback | ||
addTask(function(complete){ | ||
setTimeout(function(){ | ||
complete(null, 'sub first', 'task'); | ||
},500); | ||
}); | ||
// Add a synchronous task that returns its result | ||
addTask(function(){ | ||
return 'sub second task'; | ||
}); | ||
}); | ||
// Execute our group | ||
group.run(); | ||
``` | ||
### TaskGroup API | ||
``` javascript | ||
new require('taskgroup').TaskGroup() | ||
``` | ||
- Available methods: | ||
- `constructor(name?,fn?)` - create our new group, the arguments `name` and `fn` are optional, refer to their entries in configuration | ||
- `setConfig(config)` - set the configuration for the group, returns chain | ||
- `addTask(args...)` - create a new task item with the arguments and adds it to the group, returns the new task item | ||
- `addGroup(args...)` - create a new group item with the arguments and adds it to the group, returns the new group item | ||
- `clear()` - remove the remaining items to be executed | ||
- `stop()` - clear and pause | ||
- `pause()` - pause the execution of the items | ||
- `run()` - start/resume executing the items, returns chain | ||
- All those of [EventEmitter2](https://github.com/hij1nx/EventEmitter2) | ||
- Available configuration: | ||
- `name`, no default - allows us to assign a name to the group, useful for debugging | ||
- `fn(addGroup,addTask)`, no default - allows us to use an inline and self-executing style for defining groups, useful for nesting | ||
- `concurrency`, defaults to `1` - how many items shall we allow to be run at the same time, set to `0` to allow unlimited | ||
- `pauseOnError`, defaults to `true` - if an error occurs in one of our items, should we stop executing any remaining items? | ||
- setting to `false` will continue with execution with the other items even if an item experiences an error | ||
- Available events: | ||
- `run()` - fired just before we execute the items | ||
- `complete(err, results)` - fired when all our items have completed | ||
- `task.run()` - fired just before a task item executes | ||
- `task.complete(err, args...)` - fired when a task item has completed | ||
- `group.run()` - fired just before a group item executes | ||
- `group.complete(err, results)` - fired when a group item has completed | ||
- `item.run()` - fired just before an item executes (fired for both sub-tasks and sub-groups) | ||
- `item.complete(err, args...)` - fired when an item has completed (fired for both sub-task and sub-groups) | ||
### Task API | ||
``` javascript | ||
new require('taskgroup').Task() | ||
``` | ||
- Available methods: | ||
- `constructor(name?,fn?)` - create our new task, the arguments `name` and `fn` are optional though `fn` must be set at some point, refer to their entries in configuration | ||
- `setConfig(config)` - set the configuration for the group, returns chain | ||
- `run()` - execute the task | ||
- Available configuration: | ||
- `name`, no default - allows us to assign a name to the group, useful for debugging | ||
- `fn(complete?)`, no default - must be set at some point, it is the function to execute for the task, if it is asynchronous it should use the completion callback provided | ||
- Available events: | ||
- `run()` - fired just before we execute the task | ||
- `complete(err, args...)` - fired when the task has completed | ||
## History | ||
@@ -45,0 +145,0 @@ You can discover the history inside the [History.md](https://github.com/bevry/taskgroup/blob/master/History.md#files) file |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
18204
6
346
152
3
1
+ Addedeventemitter2@~0.4.11
+ Addedeventemitter2@0.4.14(transitive)
- Removedtypechecker@~2.0.1