Run all plugins. Must return always non empty array with [id, level, stats, ...rest]

@param {[]} plugins
@param {string} id
@param {string} level
@param {{}} stats
@param {*} rest
@return {[]}
function applyPlugins(plugins = [], id, level, stats, ...rest) {
  if (!Array.isArray(plugins) || !plugins.every((p) => typeof p === 'function')) {
    throw new Error('Plugins MUST be an array of functions');
  }
  const args = Object.freeze(rest.map((arg) => Object.freeze(arg)));
  // mutable context object that passes into plugin function and
  // should be modified with new args or stats
  // id, level and initial arguments array MUST not be modified
  const ctx = {
    get id() {
      return id
    },
    get level() {
      return level
    },
    get arguments() {
      return args
    },
    stats,
    args: rest
  };

  plugins.forEach((pluginFn) => {
    pluginFn(ctx);
  });
  const resArgs = Array.isArray(ctx.args) && ctx.args.length ? ctx.args : ctx.arguments;
  return [id, level, ctx.stats, ...resArgs];
}