Merge tag 'v4.37.0' into next

4.37.0
This commit is contained in:
Tobias Koppers 2019-07-24 10:51:04 +02:00
commit c17dfde7a8
30 changed files with 1339 additions and 125 deletions

View File

@ -75,6 +75,16 @@ export type ExternalItem =
* via the `definition` "ArrayOfStringValues". * via the `definition` "ArrayOfStringValues".
*/ */
export type ArrayOfStringValues = string[]; export type ArrayOfStringValues = string[];
/**
* This interface was referenced by `WebpackOptions`'s JSON-Schema
* via the `definition` "FilterTypes".
*/
export type FilterTypes = FilterItemTypes | FilterItemTypes[];
/**
* This interface was referenced by `WebpackOptions`'s JSON-Schema
* via the `definition` "FilterItemTypes".
*/
export type FilterItemTypes = RegExp | string | ((value: string) => boolean);
/** /**
* One or multiple rule conditions * One or multiple rule conditions
* *
@ -256,16 +266,6 @@ export type OptimizationSplitChunksSizes =
*/ */
[k: string]: number; [k: string]: number;
}; };
/**
* This interface was referenced by `WebpackOptions`'s JSON-Schema
* via the `definition` "FilterTypes".
*/
export type FilterTypes = FilterItemTypes | FilterItemTypes[];
/**
* This interface was referenced by `WebpackOptions`'s JSON-Schema
* via the `definition` "FilterItemTypes".
*/
export type FilterItemTypes = RegExp | string | Function;
export interface WebpackOptions { export interface WebpackOptions {
/** /**
@ -314,6 +314,19 @@ export interface WebpackOptions {
* Specify dependencies that shouldn't be resolved by webpack, but should become dependencies of the resulting bundle. The kind of the dependency depends on `output.libraryTarget`. * Specify dependencies that shouldn't be resolved by webpack, but should become dependencies of the resulting bundle. The kind of the dependency depends on `output.libraryTarget`.
*/ */
externals?: Externals; externals?: Externals;
/**
* Options for infrastructure level logging
*/
infrastructureLogging?: {
/**
* Enable debug logging for specific loggers
*/
debug?: FilterTypes | boolean;
/**
* Log level
*/
level?: "none" | "error" | "warn" | "info" | "log" | "verbose";
};
/** /**
* Custom values available in the loader context. * Custom values available in the loader context.
*/ */
@ -1435,6 +1448,18 @@ export interface StatsOptions {
* add the hash of the compilation * add the hash of the compilation
*/ */
hash?: boolean; hash?: boolean;
/**
* add logging output
*/
logging?: boolean | ("none" | "error" | "warn" | "info" | "log" | "verbose");
/**
* Include debug logging of specified loggers (i. e. for plugins or loaders). Filters can be Strings, RegExps or Functions
*/
loggingDebug?: FilterTypes | boolean;
/**
* add stack traces to logging output
*/
loggingTrace?: boolean;
/** /**
* Set the maximum number of modules to be shown * Set the maximum number of modules to be shown
*/ */

View File

@ -23,6 +23,7 @@ const ChunkRenderError = require("./ChunkRenderError");
const ChunkTemplate = require("./ChunkTemplate"); const ChunkTemplate = require("./ChunkTemplate");
const DependencyTemplates = require("./DependencyTemplates"); const DependencyTemplates = require("./DependencyTemplates");
const Entrypoint = require("./Entrypoint"); const Entrypoint = require("./Entrypoint");
const ErrorHelpers = require("./ErrorHelpers");
const FileSystemInfo = require("./FileSystemInfo"); const FileSystemInfo = require("./FileSystemInfo");
const { const {
connectChunkGroupAndChunk, connectChunkGroupAndChunk,
@ -41,6 +42,7 @@ const RuntimeGlobals = require("./RuntimeGlobals");
const RuntimeTemplate = require("./RuntimeTemplate"); const RuntimeTemplate = require("./RuntimeTemplate");
const Stats = require("./Stats"); const Stats = require("./Stats");
const WebpackError = require("./WebpackError"); const WebpackError = require("./WebpackError");
const { Logger, LogType } = require("./logging/Logger");
const StatsFactory = require("./stats/StatsFactory"); const StatsFactory = require("./stats/StatsFactory");
const StatsPrinter = require("./stats/StatsPrinter"); const StatsPrinter = require("./stats/StatsPrinter");
const AsyncQueue = require("./util/AsyncQueue"); const AsyncQueue = require("./util/AsyncQueue");
@ -127,6 +129,14 @@ const { arrayToSetDeprecation } = require("./util/deprecation");
* @property {(Record<string, (length: number) => string>)=} contentHashWithLength * @property {(Record<string, (length: number) => string>)=} contentHashWithLength
*/ */
/**
* @typedef {Object} LogEntry
* @property {string} type
* @property {any[]} args
* @property {number} time
* @property {string[]=} trace
*/
/** /**
* @typedef {Object} ModulePathData * @typedef {Object} ModulePathData
* @property {string|number} id * @property {string|number} id
@ -405,6 +415,9 @@ class Compilation {
"compilerIndex" "compilerIndex"
]), ]),
/** @type {SyncBailHook<[string, LogEntry], true>} */
log: new SyncBailHook(["origin", "logEntry"]),
/** @type {HookMap<SyncHook<[Object, Object]>>} */ /** @type {HookMap<SyncHook<[Object, Object]>>} */
statsPreset: new HookMap(() => new SyncHook(["options", "context"])), statsPreset: new HookMap(() => new SyncHook(["options", "context"])),
/** @type {SyncHook<[Object, Object]>} */ /** @type {SyncHook<[Object, Object]>} */
@ -520,6 +533,8 @@ class Compilation {
this.warnings = []; this.warnings = [];
/** @type {Compilation[]} */ /** @type {Compilation[]} */
this.children = []; this.children = [];
/** @type {Map<string, LogEntry[]>} */
this.logging = new Map();
/** @type {Map<DepConstructor, ModuleFactory>} */ /** @type {Map<DepConstructor, ModuleFactory>} */
this.dependencyFactories = new Map(); this.dependencyFactories = new Map();
/** @type {DependencyTemplates} */ /** @type {DependencyTemplates} */
@ -582,6 +597,69 @@ class Compilation {
return statsPrinter; return statsPrinter;
} }
/**
* @param {string | (function(): string)} name name of the logger, or function called once to get the logger name
* @returns {Logger} a logger with that name
*/
getLogger(name) {
if (!name) {
throw new TypeError("Compilation.getLogger(name) called without a name");
}
/** @type {LogEntry[] | undefined} */
let logEntries;
return new Logger((type, args) => {
if (typeof name === "function") {
name = name();
if (!name) {
throw new TypeError(
"Compilation.getLogger(name) called with a function not returning a name"
);
}
}
let trace;
switch (type) {
case LogType.warn:
case LogType.error:
case LogType.trace:
trace = ErrorHelpers.cutOffLoaderExecution(new Error("Trace").stack)
.split("\n")
.slice(3);
break;
}
/** @type {LogEntry} */
const logEntry = {
time: Date.now(),
type,
args,
trace
};
if (this.hooks.log.call(name, logEntry) === undefined) {
if (logEntry.type === LogType.profileEnd) {
// eslint-disable-next-line node/no-unsupported-features/node-builtins
if (typeof console.profileEnd === "function") {
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.profileEnd(`[${name}] ${logEntry.args[0]}`);
}
}
if (logEntries === undefined) {
logEntries = this.logging.get(name);
if (logEntries === undefined) {
logEntries = [];
this.logging.set(name, logEntries);
}
}
logEntries.push(logEntry);
if (logEntry.type === LogType.profile) {
// eslint-disable-next-line node/no-unsupported-features/node-builtins
if (typeof console.profile === "function") {
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.profile(`[${name}] ${logEntry.args[0]}`);
}
}
}
});
}
/** /**
* @param {Module} module module to be added that was created * @param {Module} module module to be added that was created
* @param {ModuleCallback} callback returns the module in the compilation, * @param {ModuleCallback} callback returns the module in the compilation,

View File

@ -24,6 +24,7 @@ const RequestShortener = require("./RequestShortener");
const ResolverFactory = require("./ResolverFactory"); const ResolverFactory = require("./ResolverFactory");
const Stats = require("./Stats"); const Stats = require("./Stats");
const Watching = require("./Watching"); const Watching = require("./Watching");
const { Logger } = require("./logging/Logger");
const { join, dirname, mkdirp } = require("./util/fs"); const { join, dirname, mkdirp } = require("./util/fs");
const { makePathsRelative } = require("./util/identifier"); const { makePathsRelative } = require("./util/identifier");
@ -133,6 +134,9 @@ class Compiler {
/** @type {SyncHook<[]>} */ /** @type {SyncHook<[]>} */
watchClose: new SyncHook([]), watchClose: new SyncHook([]),
/** @type {SyncBailHook<[string, string, any[]], true>} */
infrastructurelog: new SyncBailHook(["origin", "type", "args"]),
// TODO the following hooks are weirdly located here // TODO the following hooks are weirdly located here
// TODO move them for webpack 5 // TODO move them for webpack 5
/** @type {SyncHook<[]>} */ /** @type {SyncHook<[]>} */
@ -178,6 +182,8 @@ class Compiler {
/** @type {ResolverFactory} */ /** @type {ResolverFactory} */
this.resolverFactory = new ResolverFactory(); this.resolverFactory = new ResolverFactory();
this.infrastructureLogger = undefined;
/** @type {WebpackOptions} */ /** @type {WebpackOptions} */
this.options = /** @type {WebpackOptions} */ ({}); this.options = /** @type {WebpackOptions} */ ({});
@ -201,6 +207,33 @@ class Compiler {
this._assetEmittingWrittenFiles = new Map(); this._assetEmittingWrittenFiles = new Map();
} }
/**
* @param {string | (function(): string)} name name of the logger, or function called once to get the logger name
* @returns {Logger} a logger with that name
*/
getInfrastructureLogger(name) {
if (!name) {
throw new TypeError(
"Compiler.getInfrastructureLogger(name) called without a name"
);
}
return new Logger((type, args) => {
if (typeof name === "function") {
name = name();
if (!name) {
throw new TypeError(
"Compiler.getInfrastructureLogger(name) called with a function not returning a name"
);
}
}
if (this.hooks.infrastructurelog.call(name, type, args) === undefined) {
if (this.infrastructureLogger !== undefined) {
this.infrastructureLogger(name, type, args);
}
}
});
}
/** /**
* @param {WatchOptions} watchOptions the watcher's options * @param {WatchOptions} watchOptions the watcher's options
* @param {Callback<Stats>} handler signals when the call finishes * @param {Callback<Stats>} handler signals when the call finishes

View File

@ -248,16 +248,20 @@ class NormalModule extends Module {
createLoaderContext(resolver, options, compilation, fs) { createLoaderContext(resolver, options, compilation, fs) {
const requestShortener = compilation.runtimeTemplate.requestShortener; const requestShortener = compilation.runtimeTemplate.requestShortener;
const getCurrentLoaderName = () => {
const currentLoader = this.getCurrentLoader(loaderContext);
if (!currentLoader) return "(not in loader scope)";
return requestShortener.shorten(currentLoader.loader);
};
const loaderContext = { const loaderContext = {
version: 2, version: 2,
emitWarning: warning => { emitWarning: warning => {
if (!(warning instanceof Error)) { if (!(warning instanceof Error)) {
warning = new NonErrorEmittedError(warning); warning = new NonErrorEmittedError(warning);
} }
const currentLoader = this.getCurrentLoader(loaderContext);
this.warnings.push( this.warnings.push(
new ModuleWarning(warning, { new ModuleWarning(warning, {
from: requestShortener.shorten(currentLoader.loader) from: getCurrentLoaderName()
}) })
); );
}, },
@ -265,13 +269,20 @@ class NormalModule extends Module {
if (!(error instanceof Error)) { if (!(error instanceof Error)) {
error = new NonErrorEmittedError(error); error = new NonErrorEmittedError(error);
} }
const currentLoader = this.getCurrentLoader(loaderContext);
this.errors.push( this.errors.push(
new ModuleError(error, { new ModuleError(error, {
from: requestShortener.shorten(currentLoader.loader) from: getCurrentLoaderName()
}) })
); );
}, },
getLogger: name => {
const currentLoader = this.getCurrentLoader(loaderContext);
return compilation.getLogger(() =>
[currentLoader && currentLoader.loader, name, this.identifier()]
.filter(Boolean)
.join("|")
);
},
resolve(context, request, callback) { resolve(context, request, callback) {
resolver.resolve({}, context, request, {}, callback); resolver.resolve({}, context, request, {}, callback);
}, },

View File

@ -443,6 +443,12 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
this.set("resolveLoader.mainFields", ["loader", "main"]); this.set("resolveLoader.mainFields", ["loader", "main"]);
this.set("resolveLoader.extensions", [".js"]); this.set("resolveLoader.extensions", [".js"]);
this.set("resolveLoader.mainFiles", ["index"]); this.set("resolveLoader.mainFiles", ["index"]);
this.set("infrastructureLogging", "call", value =>
Object.assign({}, value)
);
this.set("infrastructureLogging.level", "info");
this.set("infrastructureLogging.debug", false);
} }
} }

126
lib/logging/Logger.js Normal file
View File

@ -0,0 +1,126 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
/**
* @enum {string}
*/
const LogType = Object.freeze({
error: "error", // message, c style arguments
warn: "warn", // message, c style arguments
info: "info", // message, c style arguments
log: "log", // message, c style arguments
debug: "debug", // message, c style arguments
trace: "trace", // no arguments
group: "group", // [label]
groupCollapsed: "groupCollapsed", // [label]
groupEnd: "groupEnd", // [label]
profile: "profile", // [profileName]
profileEnd: "profileEnd", // [profileName]
time: "time", // name, time as [seconds, nanoseconds]
clear: "clear" // no arguments
});
exports.LogType = LogType;
/** @typedef {LogType} LogTypeEnum */
const LOG_SYMBOL = Symbol("webpack logger raw log method");
const TIMERS_SYMBOL = Symbol("webpack logger times");
class WebpackLogger {
/**
* @param {function(LogType, any[]=): void} log log function
*/
constructor(log) {
this[LOG_SYMBOL] = log;
}
error(...args) {
this[LOG_SYMBOL](LogType.error, args);
}
warn(...args) {
this[LOG_SYMBOL](LogType.warn, args);
}
info(...args) {
this[LOG_SYMBOL](LogType.info, args);
}
log(...args) {
this[LOG_SYMBOL](LogType.log, args);
}
debug(...args) {
this[LOG_SYMBOL](LogType.debug, args);
}
assert(assertion, ...args) {
if (!assertion) {
this[LOG_SYMBOL](LogType.error, args);
}
}
trace() {
this[LOG_SYMBOL](LogType.trace, ["Trace"]);
}
clear() {
this[LOG_SYMBOL](LogType.clear);
}
group(...args) {
this[LOG_SYMBOL](LogType.group, args);
}
groupCollapsed(...args) {
this[LOG_SYMBOL](LogType.groupCollapsed, args);
}
groupEnd(...args) {
this[LOG_SYMBOL](LogType.groupEnd, args);
}
profile(label) {
this[LOG_SYMBOL](LogType.profile, [label]);
}
profileEnd(label) {
this[LOG_SYMBOL](LogType.profileEnd, [label]);
}
time(label) {
this[TIMERS_SYMBOL] = this[TIMERS_SYMBOL] || new Map();
this[TIMERS_SYMBOL].set(label, process.hrtime());
}
timeLog(label) {
const prev = this[TIMERS_SYMBOL] && this[TIMERS_SYMBOL].get(label);
if (!prev) {
throw new Error(`No such label '${label}' for WebpackLogger.timeLog()`);
}
const time = process.hrtime(prev);
this[LOG_SYMBOL](LogType.time, [label, ...time]);
}
timeEnd(label) {
const prev = this[TIMERS_SYMBOL] && this[TIMERS_SYMBOL].get(label);
if (!prev) {
throw new Error(`No such label '${label}' for WebpackLogger.timeEnd()`);
}
const time = process.hrtime(prev);
this[TIMERS_SYMBOL].delete(label);
this[LOG_SYMBOL](LogType.time, [label, ...time]);
}
}
exports.Logger = WebpackLogger;

View File

@ -0,0 +1,188 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const { LogType } = require("./Logger");
/** @typedef {import("../../declarations/WebpackOptions").FilterItemTypes} FilterItemTypes */
/** @typedef {import("../../declarations/WebpackOptions").FilterTypes} FilterTypes */
/** @typedef {import("./Logger").LogTypeEnum} LogTypeEnum */
/** @typedef {function(string): boolean} FilterFunction */
/**
* @typedef {Object} LoggerOptions
* @property {false|true|"none"|"error"|"warn"|"info"|"log"|"verbose"} options.level loglevel
* @property {FilterTypes|boolean} options.debug filter for debug logging
*/
/**
* @param {FilterItemTypes} item an input item
* @returns {FilterFunction} filter funtion
*/
const filterToFunction = item => {
if (typeof item === "string") {
const regExp = new RegExp(
`[\\\\/]${item.replace(
// eslint-disable-next-line no-useless-escape
/[-[\]{}()*+?.\\^$|]/g,
"\\$&"
)}([\\\\/]|$|!|\\?)`
);
return ident => regExp.test(ident);
}
if (item && typeof item === "object" && typeof item.test === "function") {
return ident => item.test(ident);
}
if (typeof item === "function") {
return item;
}
if (typeof item === "boolean") {
return () => item;
}
};
/**
* @enum {number} */
const LogLevel = {
none: 6,
false: 6,
error: 5,
warn: 4,
info: 3,
log: 2,
true: 2,
verbose: 1
};
/**
* @param {LoggerOptions} options options object
* @returns {function(string, LogTypeEnum, any[]): void} logging function
*/
module.exports = ({ level = "info", debug = false }) => {
const debugFilters =
typeof debug === "boolean"
? [() => debug]
: /** @type {FilterItemTypes[]} */ ([])
.concat(debug)
.map(filterToFunction);
/** @type {number} */
const loglevel = LogLevel[`${level}`] || 0;
/**
* @param {string} name name of the logger
* @param {LogTypeEnum} type type of the log entry
* @param {any[]} args arguments of the log entry
* @returns {void}
*/
const logger = (name, type, args) => {
const labeledArgs = (prefix = "") => {
if (Array.isArray(args)) {
if (args.length > 0 && typeof args[0] === "string") {
return [`${prefix}[${name}] ${args[0]}`, ...args.slice(1)];
} else {
return [`${prefix}[${name}]`, ...args];
}
} else {
return [];
}
};
const debug = debugFilters.some(f => f(name));
switch (type) {
case LogType.debug:
if (!debug) return;
// eslint-disable-next-line node/no-unsupported-features/node-builtins
if (typeof console.debug === "function") {
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.debug(...labeledArgs());
} else {
console.log(...labeledArgs());
}
break;
case LogType.log:
if (!debug && loglevel > LogLevel.log) return;
console.log(...labeledArgs());
break;
case LogType.info:
if (!debug && loglevel > LogLevel.info) return;
console.info(...labeledArgs("<i> "));
break;
case LogType.warn:
if (!debug && loglevel > LogLevel.warn) return;
console.warn(...labeledArgs("<w> "));
break;
case LogType.error:
if (!debug && loglevel > LogLevel.error) return;
console.error(...labeledArgs("<e> "));
break;
case LogType.trace:
if (!debug) return;
console.trace();
break;
case LogType.group:
if (!debug && loglevel > LogLevel.log) return;
// eslint-disable-next-line node/no-unsupported-features/node-builtins
if (typeof console.group === "function") {
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.group(...labeledArgs());
} else {
console.log(...labeledArgs());
}
break;
case LogType.groupCollapsed:
if (!debug && loglevel > LogLevel.log) return;
// eslint-disable-next-line node/no-unsupported-features/node-builtins
if (typeof console.groupCollapsed === "function") {
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.groupCollapsed(...labeledArgs());
} else {
console.log(...labeledArgs("<g> "));
}
break;
case LogType.groupEnd:
if (!debug && loglevel > LogLevel.log) return;
// eslint-disable-next-line node/no-unsupported-features/node-builtins
if (typeof console.groupEnd === "function") {
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.groupEnd();
} else {
console.log(...labeledArgs("</g> "));
}
break;
case LogType.time:
if (!debug && loglevel > LogLevel.log) return;
console.log(
`[${name}] ${args[0]}: ${args[1] * 1000 + args[2] / 1000000}ms`
);
break;
case LogType.profile:
// eslint-disable-next-line node/no-unsupported-features/node-builtins
if (typeof console.profile === "function") {
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.profile(...labeledArgs());
}
break;
case LogType.profileEnd:
// eslint-disable-next-line node/no-unsupported-features/node-builtins
if (typeof console.profileEnd === "function") {
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.profileEnd(...labeledArgs());
}
break;
case LogType.clear:
if (!debug && loglevel > LogLevel.log) return;
// eslint-disable-next-line node/no-unsupported-features/node-builtins
if (typeof console.clear === "function") {
// eslint-disable-next-line node/no-unsupported-features/node-builtins
console.clear();
}
break;
default:
throw new Error(`Unexpected LogType ${type}`);
}
};
return logger;
};

42
lib/logging/runtime.js Normal file
View File

@ -0,0 +1,42 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const SyncBailHook = require("tapable/lib/SyncBailHook");
const { Logger } = require("./Logger");
const createConsoleLogger = require("./createConsoleLogger");
/** @type {createConsoleLogger.LoggerOptions} */
let currentDefaultLoggerOptions = {
level: "info",
debug: false
};
let currentDefaultLogger = createConsoleLogger(currentDefaultLoggerOptions);
/**
* @param {string} name name of the logger
* @returns {Logger} a logger
*/
exports.getLogger = name => {
return new Logger((type, args) => {
if (exports.hooks.log.call(name, type, args) === undefined) {
currentDefaultLogger(name, type, args);
}
});
};
/**
* @param {createConsoleLogger.LoggerOptions} options new options, merge with old options
* @returns {void}
*/
exports.configureDefaultLogger = options => {
Object.assign(currentDefaultLoggerOptions, options);
currentDefaultLogger = createConsoleLogger(currentDefaultLoggerOptions);
};
exports.hooks = {
log: new SyncBailHook(["origin", "type", "args"])
};

View File

@ -7,16 +7,30 @@
const CachedInputFileSystem = require("enhanced-resolve/lib/CachedInputFileSystem"); const CachedInputFileSystem = require("enhanced-resolve/lib/CachedInputFileSystem");
const fs = require("graceful-fs"); const fs = require("graceful-fs");
const createConsoleLogger = require("../logging/createConsoleLogger");
const NodeWatchFileSystem = require("./NodeWatchFileSystem"); const NodeWatchFileSystem = require("./NodeWatchFileSystem");
/** @typedef {import("../Compiler")} Compiler */ /** @typedef {import("../Compiler")} Compiler */
class NodeEnvironmentPlugin { class NodeEnvironmentPlugin {
constructor(options) {
this.options = options || {};
}
/** /**
* @param {Compiler} compiler the compiler instance * @param {Compiler} compiler the compiler instance
* @returns {void} * @returns {void}
*/ */
apply(compiler) { apply(compiler) {
compiler.infrastructureLogger = createConsoleLogger(
Object.assign(
{
level: "info",
debug: false
},
this.options.infrastructureLogging
)
);
compiler.inputFileSystem = new CachedInputFileSystem(fs, 60000); compiler.inputFileSystem = new CachedInputFileSystem(fs, 60000);
const inputFileSystem = compiler.inputFileSystem; const inputFileSystem = compiler.inputFileSystem;
compiler.outputFileSystem = fs; compiler.outputFileSystem = fs;

View File

@ -6,6 +6,7 @@
"use strict"; "use strict";
const formatLocation = require("../formatLocation"); const formatLocation = require("../formatLocation");
const { LogType } = require("../logging/Logger");
const AggressiveSplittingPlugin = require("../optimize/AggressiveSplittingPlugin"); const AggressiveSplittingPlugin = require("../optimize/AggressiveSplittingPlugin");
const ConcatenatedModule = require("../optimize/ConcatenatedModule"); const ConcatenatedModule = require("../optimize/ConcatenatedModule");
const SizeLimitsPlugin = require("../performance/SizeLimitsPlugin"); const SizeLimitsPlugin = require("../performance/SizeLimitsPlugin");
@ -19,6 +20,7 @@ const {
compareModulesById, compareModulesById,
compareModulesByIdOrIdentifier compareModulesByIdOrIdentifier
} = require("../util/comparators"); } = require("../util/comparators");
const identifierUtils = require("../util/identifier");
/** @typedef {import("webpack-sources").Source} Source */ /** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../Chunk")} Chunk */ /** @typedef {import("../Chunk")} Chunk */
@ -46,6 +48,7 @@ const {
/** /**
* @typedef {Object} UsualOptions * @typedef {Object} UsualOptions
* @property {string} context
* @property {RequestShortener} requestShortener * @property {RequestShortener} requestShortener
* @property {string} chunksSort * @property {string} chunksSort
* @property {string} modulesSort * @property {string} modulesSort
@ -54,6 +57,9 @@ const {
* @property {Function[]} excludeModules * @property {Function[]} excludeModules
* @property {Function[]} warningsFilter * @property {Function[]} warningsFilter
* @property {number} maxModules * @property {number} maxModules
* @property {false|"none"|"error"|"warn"|"info"|"log"|"verbose"} logging
* @property {Function[]} loggingDebug
* @property {boolean} loggingTrace
* @property {any} _env * @property {any} _env
*/ */
@ -280,6 +286,128 @@ const SIMPLE_EXTRACTORS = {
context context
); );
}, },
logging: (object, compilation, _context, options, factory) => {
const util = require("util");
const { loggingDebug, loggingTrace, context } = options;
object.logging = {};
let acceptedTypes;
let collapsedGroups = false;
switch (options.logging) {
case "none":
acceptedTypes = new Set([]);
break;
case "error":
acceptedTypes = new Set([LogType.error]);
break;
case "warn":
acceptedTypes = new Set([LogType.error, LogType.warn]);
break;
case "info":
acceptedTypes = new Set([LogType.error, LogType.warn, LogType.info]);
break;
case "log":
acceptedTypes = new Set([
LogType.error,
LogType.warn,
LogType.info,
LogType.log,
LogType.group,
LogType.groupEnd,
LogType.groupCollapsed,
LogType.clear
]);
break;
case "verbose":
acceptedTypes = new Set([
LogType.error,
LogType.warn,
LogType.info,
LogType.log,
LogType.group,
LogType.groupEnd,
LogType.groupCollapsed,
LogType.profile,
LogType.profileEnd,
LogType.time,
LogType.clear
]);
collapsedGroups = true;
break;
}
let depthInCollapsedGroup = 0;
for (const [origin, logEntries] of compilation.logging) {
const debugMode = loggingDebug.some(fn => fn(origin));
const groupStack = [];
const rootList = [];
let currentList = rootList;
let processedLogEntries = 0;
for (const entry of logEntries) {
let type = entry.type;
if (!debugMode && !acceptedTypes.has(type)) continue;
// Expand groups in verbose and debug modes
if (type === LogType.groupCollapsed && (debugMode || collapsedGroups))
type = LogType.group;
if (depthInCollapsedGroup === 0) {
processedLogEntries++;
}
if (type === LogType.groupEnd) {
groupStack.pop();
if (groupStack.length > 0) {
currentList = groupStack[groupStack.length - 1].children;
} else {
currentList = rootList;
}
if (depthInCollapsedGroup > 0) depthInCollapsedGroup--;
continue;
}
let message = undefined;
if (entry.type === LogType.time) {
message = `${entry.args[0]}: ${entry.args[1] * 1000 +
entry.args[2] / 1000000}ms`;
} else if (entry.args && entry.args.length > 0) {
message = util.format(entry.args[0], ...entry.args.slice(1));
}
const newEntry = {
...entry,
type,
message,
trace: loggingTrace ? entry.trace : undefined,
children:
type === LogType.group || type === LogType.groupCollapsed
? []
: undefined
};
currentList.push(newEntry);
if (newEntry.children) {
groupStack.push(newEntry);
currentList = newEntry.children;
if (depthInCollapsedGroup > 0) {
depthInCollapsedGroup++;
} else if (type === LogType.groupCollapsed) {
depthInCollapsedGroup = 1;
}
}
}
let name = identifierUtils
.makePathsRelative(context, origin, compilation.cache)
.replace(/\|/g, " ");
if (name in object.logging) {
let i = 1;
while (`${name}#${i}` in object.logging) {
i++;
}
name = `${name}#${i}`;
}
object.logging[name] = {
entries: rootList,
filteredEntries: logEntries.length - processedLogEntries,
debug: debugMode
};
}
},
children: (object, compilation, context, options, factory) => { children: (object, compilation, context, options, factory) => {
const { type } = context; const { type } = context;
object.children = factory.create( object.children = factory.create(

View File

@ -36,6 +36,7 @@ const NAMED_PRESETS = {
optimizationBailout: true, optimizationBailout: true,
errorDetails: true, errorDetails: true,
publicPath: true, publicPath: true,
logging: "verbose",
orphanModules: true, orphanModules: true,
runtime: true, runtime: true,
exclude: false, exclude: false,
@ -55,6 +56,7 @@ const NAMED_PRESETS = {
optimizationBailout: true, optimizationBailout: true,
errorDetails: true, errorDetails: true,
publicPath: true, publicPath: true,
logging: true,
runtimeModules: true, runtimeModules: true,
runtime: true, runtime: true,
exclude: false, exclude: false,
@ -65,17 +67,20 @@ const NAMED_PRESETS = {
modules: true, modules: true,
maxModules: 0, maxModules: 0,
errors: true, errors: true,
warnings: true warnings: true,
logging: "warn"
}, },
"errors-only": { "errors-only": {
all: false, all: false,
errors: true, errors: true,
moduleTrace: true moduleTrace: true,
logging: "error"
}, },
"errors-warnings": { "errors-warnings": {
all: false, all: false,
errors: true, errors: true,
warnings: true warnings: true,
logging: "warn"
}, },
none: { none: {
all: false all: false
@ -132,6 +137,10 @@ const DEFAULTS = {
errorDetails: OFF_FOR_TO_STRING, errorDetails: OFF_FOR_TO_STRING,
warnings: NORMAL_ON, warnings: NORMAL_ON,
publicPath: OFF_FOR_TO_STRING, publicPath: OFF_FOR_TO_STRING,
logging: ({ all }, { forToString }) =>
(forToString && all !== false ? "info" : false),
loggingDebug: () => [],
loggingTrace: OFF_FOR_TO_STRING,
excludeModules: () => [], excludeModules: () => [],
excludeAssets: () => [], excludeAssets: () => [],
maxModules: (o, { forToString }) => ((forToString ? 15 : Infinity)), maxModules: (o, { forToString }) => ((forToString ? 15 : Infinity)),
@ -142,7 +151,7 @@ const DEFAULTS = {
colors: () => false colors: () => false
}; };
const normalizeExclude = item => { const normalizeFilter = item => {
if (typeof item === "string") { if (typeof item === "string") {
const regExp = new RegExp( const regExp = new RegExp(
`[\\\\/]${item.replace( `[\\\\/]${item.replace(
@ -169,13 +178,13 @@ const NORMALIZER = {
if (!Array.isArray(value)) { if (!Array.isArray(value)) {
value = value ? [value] : []; value = value ? [value] : [];
} }
return value.map(normalizeExclude); return value.map(normalizeFilter);
}, },
excludeAssets: value => { excludeAssets: value => {
if (!Array.isArray(value)) { if (!Array.isArray(value)) {
value = value ? [value] : []; value = value ? [value] : [];
} }
return value.map(normalizeExclude); return value.map(normalizeFilter);
}, },
warningsFilter: value => { warningsFilter: value => {
if (!Array.isArray(value)) { if (!Array.isArray(value)) {
@ -195,6 +204,16 @@ const NORMALIZER = {
`Can only filter warnings with Strings or RegExps. (Given: ${filter})` `Can only filter warnings with Strings or RegExps. (Given: ${filter})`
); );
}); });
},
logging: value => {
if (value === true) value = "log";
return value;
},
loggingDebug: value => {
if (!Array.isArray(value)) {
value = value ? [value] : [];
}
return value.map(normalizeFilter);
} }
}; };

View File

@ -43,6 +43,12 @@ const printSizes = (sizes, { formatSize }) => {
} }
}; };
const mapLines = (str, fn) =>
str
.split("\n")
.map(fn)
.join("\n");
/** /**
* @param {number} n a number * @param {number} n a number
* @returns {string} number as two digit string, leading 0 * @returns {string} number as two digit string, leading 0
@ -130,6 +136,14 @@ const SIMPLE_PRINTERS = {
: filteredAssets : filteredAssets
} ${plural(filteredAssets, "asset", "assets")}` } ${plural(filteredAssets, "asset", "assets")}`
: undefined, : undefined,
"compilation.logging": (logging, context, printer) =>
Array.isArray(logging)
? undefined
: printer.print(
context.type,
Object.entries(logging).map(([name, value]) => ({ ...value, name })),
context
),
"compilation.children[].compilation.name": name => "compilation.children[].compilation.name": name =>
name ? `Child ${name}:` : "Child", name ? `Child ${name}:` : "Child",
@ -402,12 +416,45 @@ const SIMPLE_PRINTERS = {
"error.moduleTrace": moduleTrace => undefined, "error.moduleTrace": moduleTrace => undefined,
"error.separator!": () => "\n", "error.separator!": () => "\n",
"loggingEntry(error).loggingEntry.message": (message, { red }) =>
mapLines(message, x => `<e> ${red(x)}`),
"loggingEntry(warn).loggingEntry.message": (message, { yellow }) =>
mapLines(message, x => `<w> ${yellow(x)}`),
"loggingEntry(info).loggingEntry.message": (message, { green }) =>
mapLines(message, x => `<i> ${green(x)}`),
"loggingEntry(log).loggingEntry.message": (message, { bold }) =>
mapLines(message, x => bold(x)),
"loggingEntry(debug).loggingEntry.message": message => message,
"loggingEntry(trace).loggingEntry.message": message => message,
"loggingEntry(profile).loggingEntry.message": (message, { magenta }) =>
mapLines(message, x => `<p> ${magenta(x)}`),
"loggingEntry(profileEnd).loggingEntry.message": (message, { magenta }) =>
mapLines(message, x => `</p> ${magenta(x)}`),
"loggingEntry(time).loggingEntry.message": (message, { magenta }) =>
mapLines(message, x => `<t> ${magenta(x)}`),
"loggingEntry(group).loggingEntry.message": (message, { cyan }) =>
mapLines(message, x => cyan(x)),
"loggingEntry(groupCollapsed).loggingEntry.message": (message, { cyan }) =>
mapLines(message, x => `<+> ${cyan(x)}`),
"loggingEntry(clear).loggingEntry": () => "-------",
"loggingEntry(groupCollapsed).loggingEntry.children": () => "",
"loggingEntry.trace[]": trace =>
trace ? mapLines(trace, x => `| ${x}`) : undefined,
"moduleTraceItem.originName": originName => originName, "moduleTraceItem.originName": originName => originName,
loggingGroup: loggingGroup =>
loggingGroup.entries.length === 0 ? "" : undefined,
"loggingGroup.debug": (flag, { red }) => ((flag ? red("DEBUG") : undefined)),
"loggingGroup.name": (name, { bold }) => bold(`LOG from ${name}`),
"loggingGroup.separator!": () => "\n",
"loggingGroup.filteredEntries": filteredEntries =>
filteredEntries > 0 ? `+ ${filteredEntries} hidden lines` : undefined,
"moduleTraceDependency.loc": loc => loc "moduleTraceDependency.loc": loc => loc
}; };
/** @type {Record<string, string>} */ /** @type {Record<string, string | Function>} */
const ITEM_NAMES = { const ITEM_NAMES = {
"compilation.assets[]": "asset", "compilation.assets[]": "asset",
"compilation.modules[]": "module", "compilation.modules[]": "module",
@ -416,6 +463,7 @@ const ITEM_NAMES = {
"compilation.namedChunkGroups[]": "chunkGroup", "compilation.namedChunkGroups[]": "chunkGroup",
"compilation.errors[]": "error", "compilation.errors[]": "error",
"compilation.warnings[]": "error", "compilation.warnings[]": "error",
"compilation.logging[]": "loggingGroup",
"compilation.children[]": "compilation", "compilation.children[]": "compilation",
"asset.chunks[]": "assetChunk", "asset.chunks[]": "assetChunk",
"asset.auxiliaryChunks[]": "assetChunk", "asset.auxiliaryChunks[]": "assetChunk",
@ -427,6 +475,10 @@ const ITEM_NAMES = {
"chunk.origins[]": "chunkOrigin", "chunk.origins[]": "chunkOrigin",
"chunk.rootModules[]": "module", "chunk.rootModules[]": "module",
"chunk.modules[]": "module", "chunk.modules[]": "module",
"loggingGroup.entries[]": logEntry =>
`loggingEntry(${logEntry.type}).loggingEntry`,
"loggingEntry.children[]": logEntry =>
`loggingEntry(${logEntry.type}).loggingEntry`,
"error.moduleTrace[]": "moduleTraceItem", "error.moduleTrace[]": "moduleTraceItem",
"moduleTraceItem.dependencies[]": "moduleTraceDependency" "moduleTraceItem.dependencies[]": "moduleTraceDependency"
}; };
@ -467,6 +519,7 @@ const PREFERED_ORDERS = {
"chunks", "chunks",
"modules", "modules",
"filteredModules", "filteredModules",
"logging",
"warnings", "warnings",
"errors", "errors",
"children", "children",
@ -572,6 +625,15 @@ const PREFERED_ORDERS = {
error: ERROR_PREFERED_ORDER, error: ERROR_PREFERED_ORDER,
warning: ERROR_PREFERED_ORDER, warning: ERROR_PREFERED_ORDER,
"chunk.childrenByOrder[]": ["type", "children"], "chunk.childrenByOrder[]": ["type", "children"],
loggingGroup: [
"debug",
"name",
"separator!",
"entries",
"separator!",
"filtredEntries"
],
loggingEntry: ["message", "trace", "children"],
"chunkGroup.childAssets[]": ["type", "children"] "chunkGroup.childAssets[]": ["type", "children"]
}; };
@ -608,7 +670,10 @@ const SIMPLE_ITEMS_JOINER = {
.join(" "), .join(" "),
"compilation.errors": itemsJoinMoreSpacing, "compilation.errors": itemsJoinMoreSpacing,
"compilation.warnings": itemsJoinMoreSpacing, "compilation.warnings": itemsJoinMoreSpacing,
"compilation.logging": itemsJoinMoreSpacing,
"moduleTraceItem.dependencies": itemsJoinOneLine, "moduleTraceItem.dependencies": itemsJoinOneLine,
"loggingEntry.children": items =>
indent(items.filter(Boolean).join("\n"), " ", false),
"compilation.children": items => "compilation.children": items =>
items.map(item => indent(item, " ", true)).join("\n") items.map(item => indent(item, " ", true)).join("\n")
}; };
@ -701,7 +766,9 @@ const SIMPLE_ELEMENT_JOINERS = {
for (const item of items) { for (const item of items) {
if (!item.content) continue; if (!item.content) continue;
const needMoreSpace = const needMoreSpace =
item.element === "warnings" || item.element === "errors"; item.element === "warnings" ||
item.element === "errors" ||
item.element === "logging";
if (result.length !== 0) { if (result.length !== 0) {
result.push(needMoreSpace || lastNeedMore ? "\n\n" : "\n"); result.push(needMoreSpace || lastNeedMore ? "\n\n" : "\n");
} }
@ -797,6 +864,7 @@ const SIMPLE_ELEMENT_JOINERS = {
chunkOrigin: items => " > " + joinOneLine(items), chunkOrigin: items => " > " + joinOneLine(items),
"errors[].error": joinError(true), "errors[].error": joinError(true),
"warnings[].error": joinError(false), "warnings[].error": joinError(false),
loggingGroup: items => joinExplicitNewLine(items, "").trimRight(),
moduleTraceItem: items => " @ " + joinOneLine(items), moduleTraceItem: items => " @ " + joinOneLine(items),
moduleTraceDependency: joinOneLine moduleTraceDependency: joinOneLine
}; };
@ -973,7 +1041,10 @@ class DefaultStatsPrinterPlugin {
const itemName = ITEM_NAMES[key]; const itemName = ITEM_NAMES[key];
stats.hooks.getItemName stats.hooks.getItemName
.for(key) .for(key)
.tap("DefaultStatsPrinterPlugin", () => itemName); .tap(
"DefaultStatsPrinterPlugin",
typeof itemName === "string" ? () => itemName : itemName
);
} }
for (const key of Object.keys(SIMPLE_ITEMS_JOINER)) { for (const key of Object.keys(SIMPLE_ITEMS_JOINER)) {

View File

@ -52,7 +52,9 @@ const createCompiler = options => {
options = new WebpackOptionsDefaulter().process(options); options = new WebpackOptionsDefaulter().process(options);
const compiler = new Compiler(options.context); const compiler = new Compiler(options.context);
compiler.options = options; compiler.options = options;
new NodeEnvironmentPlugin().apply(compiler); new NodeEnvironmentPlugin({
infrastructureLogging: options.infrastructureLogging
}).apply(compiler);
if (Array.isArray(options.plugins)) { if (Array.isArray(options.plugins)) {
for (const plugin of options.plugins) { for (const plugin of options.plugins) {
if (typeof plugin === "function") { if (typeof plugin === "function") {

View File

@ -252,7 +252,7 @@
}, },
{ {
"instanceof": "Function", "instanceof": "Function",
"tsType": "Function" "tsType": "((value: string) => boolean)"
} }
] ]
}, },
@ -2006,6 +2006,35 @@
"description": "add the hash of the compilation", "description": "add the hash of the compilation",
"type": "boolean" "type": "boolean"
}, },
"logging": {
"description": "add logging output",
"anyOf": [
{
"description": "enable/disable logging output (true: shows normal logging output, loglevel: log)",
"type": "boolean"
},
{
"description": "specify log level of logging output",
"enum": ["none", "error", "warn", "info", "log", "verbose"]
}
]
},
"loggingDebug": {
"description": "Include debug logging of specified loggers (i. e. for plugins or loaders). Filters can be Strings, RegExps or Functions",
"anyOf": [
{
"$ref": "#/definitions/FilterTypes"
},
{
"description": "Enable/Disable debug logging for all loggers",
"type": "boolean"
}
]
},
"loggingTrace": {
"description": "add stack traces to logging output",
"type": "boolean"
},
"maxModules": { "maxModules": {
"description": "Set the maximum number of modules to be shown", "description": "Set the maximum number of modules to be shown",
"type": "number" "type": "number"
@ -2263,6 +2292,29 @@
} }
] ]
}, },
"infrastructureLogging": {
"description": "Options for infrastructure level logging",
"type": "object",
"additionalProperties": false,
"properties": {
"debug": {
"description": "Enable debug logging for specific loggers",
"anyOf": [
{
"$ref": "#/definitions/FilterTypes"
},
{
"description": "Enable/Disable debug logging for all loggers",
"type": "boolean"
}
]
},
"level": {
"description": "Log level",
"enum": ["none", "error", "warn", "info", "log", "verbose"]
}
}
},
"loader": { "loader": {
"description": "Custom values available in the loader context.", "description": "Custom values available in the loader context.",
"type": "object" "type": "object"

View File

@ -709,4 +709,152 @@ describe("Compiler", () => {
done(); done();
}); });
}); });
describe("infrastructure logging", () => {
const CONSOLE_METHODS = [
"error",
"warn",
"info",
"log",
"debug",
"trace",
"profile",
"profileEnd",
"group",
"groupEnd",
"groupCollapsed"
];
const spies = {};
beforeEach(() => {
for (const method of CONSOLE_METHODS) {
if (console[method]) {
spies[method] = jest.spyOn(console, method).mockImplementation();
}
}
});
afterEach(() => {
for (const method in spies) {
spies[method].mockRestore();
delete spies[method];
}
});
class MyPlugin {
apply(compiler) {
const logger = compiler.getInfrastructureLogger("MyPlugin");
logger.time("Time");
logger.group("Group");
logger.error("Error");
logger.warn("Warning");
logger.info("Info");
logger.log("Log");
logger.debug("Debug");
logger.groupCollapsed("Collaped group");
logger.log("Log inside collapsed group");
logger.groupEnd();
logger.groupEnd();
logger.timeEnd("Time");
}
}
it("should log to the console (verbose)", done => {
const compiler = webpack({
context: path.join(__dirname, "fixtures"),
entry: "./a",
output: {
path: "/",
filename: "bundle.js"
},
infrastructureLogging: {
level: "verbose"
},
plugins: [new MyPlugin()]
});
compiler.outputFileSystem = new MemoryFs();
compiler.run((err, stats) => {
expect(spies.group).toHaveBeenCalledTimes(1);
expect(spies.group).toHaveBeenCalledWith("[MyPlugin] Group");
expect(spies.groupCollapsed).toHaveBeenCalledTimes(1);
expect(spies.groupCollapsed).toHaveBeenCalledWith(
"[MyPlugin] Collaped group"
);
expect(spies.error).toHaveBeenCalledTimes(1);
expect(spies.error).toHaveBeenCalledWith("<e> [MyPlugin] Error");
expect(spies.warn).toHaveBeenCalledTimes(1);
expect(spies.warn).toHaveBeenCalledWith("<w> [MyPlugin] Warning");
expect(spies.info).toHaveBeenCalledTimes(1);
expect(spies.info).toHaveBeenCalledWith("<i> [MyPlugin] Info");
expect(spies.log).toHaveBeenCalledTimes(3);
expect(spies.log).toHaveBeenCalledWith("[MyPlugin] Log");
expect(spies.log).toHaveBeenCalledWith(
"[MyPlugin] Log inside collapsed group"
);
expect(spies.debug).toHaveBeenCalledTimes(0);
expect(spies.groupEnd).toHaveBeenCalledTimes(2);
done();
});
});
it("should log to the console (debug mode)", done => {
const compiler = webpack({
context: path.join(__dirname, "fixtures"),
entry: "./a",
output: {
path: "/",
filename: "bundle.js"
},
infrastructureLogging: {
level: "error",
debug: /MyPlugin/
},
plugins: [new MyPlugin()]
});
compiler.outputFileSystem = new MemoryFs();
compiler.run((err, stats) => {
expect(spies.group).toHaveBeenCalledTimes(1);
expect(spies.group).toHaveBeenCalledWith("[MyPlugin] Group");
expect(spies.groupCollapsed).toHaveBeenCalledTimes(1);
expect(spies.groupCollapsed).toHaveBeenCalledWith(
"[MyPlugin] Collaped group"
);
expect(spies.error).toHaveBeenCalledTimes(1);
expect(spies.error).toHaveBeenCalledWith("<e> [MyPlugin] Error");
expect(spies.warn).toHaveBeenCalledTimes(1);
expect(spies.warn).toHaveBeenCalledWith("<w> [MyPlugin] Warning");
expect(spies.info).toHaveBeenCalledTimes(1);
expect(spies.info).toHaveBeenCalledWith("<i> [MyPlugin] Info");
expect(spies.log).toHaveBeenCalledTimes(3);
expect(spies.log).toHaveBeenCalledWith("[MyPlugin] Log");
expect(spies.log).toHaveBeenCalledWith(
"[MyPlugin] Log inside collapsed group"
);
expect(spies.debug).toHaveBeenCalledTimes(1);
expect(spies.debug).toHaveBeenCalledWith("[MyPlugin] Debug");
expect(spies.groupEnd).toHaveBeenCalledTimes(2);
done();
});
});
it("should log to the console (none)", done => {
const compiler = webpack({
context: path.join(__dirname, "fixtures"),
entry: "./a",
output: {
path: "/",
filename: "bundle.js"
},
infrastructureLogging: {
level: "none"
},
plugins: [new MyPlugin()]
});
compiler.outputFileSystem = new MemoryFs();
compiler.run((err, stats) => {
expect(spies.group).toHaveBeenCalledTimes(0);
expect(spies.groupCollapsed).toHaveBeenCalledTimes(0);
expect(spies.error).toHaveBeenCalledTimes(0);
expect(spies.warn).toHaveBeenCalledTimes(0);
expect(spies.info).toHaveBeenCalledTimes(0);
expect(spies.log).toHaveBeenCalledTimes(0);
expect(spies.debug).toHaveBeenCalledTimes(0);
expect(spies.groupEnd).toHaveBeenCalledTimes(0);
done();
});
});
});
}); });

View File

@ -259,69 +259,63 @@ describe("JavascriptParser", () => {
const state = testCases[name][1]; const state = testCases[name][1];
const testParser = new JavascriptParser({}); const testParser = new JavascriptParser({});
testParser.hooks.canRename.tap( testParser.hooks.canRename
"abc", .for("abc")
"JavascriptParserTest", .tap("JavascriptParserTest", expr => true);
expr => true testParser.hooks.canRename
); .for("ijk")
testParser.hooks.canRename.tap( .tap("JavascriptParserTest", expr => true);
"ijk", testParser.hooks.call.for("abc").tap("JavascriptParserTest", expr => {
"JavascriptParserTest",
expr => true
);
testParser.hooks.call.tap("abc", "JavascriptParserTest", expr => {
if (!testParser.state.abc) testParser.state.abc = []; if (!testParser.state.abc) testParser.state.abc = [];
testParser.state.abc.push(testParser.parseString(expr.arguments[0])); testParser.state.abc.push(testParser.parseString(expr.arguments[0]));
return true; return true;
}); });
testParser.hooks.call.tap("cde.abc", "JavascriptParserTest", expr => { testParser.hooks.call.for("cde.abc").tap("JavascriptParserTest", expr => {
if (!testParser.state.cdeabc) testParser.state.cdeabc = []; if (!testParser.state.cdeabc) testParser.state.cdeabc = [];
testParser.state.cdeabc.push(testParser.parseString(expr.arguments[0])); testParser.state.cdeabc.push(testParser.parseString(expr.arguments[0]));
return true; return true;
}); });
testParser.hooks.call.tap("cde.ddd.abc", "JavascriptParserTest", expr => { testParser.hooks.call
.for("cde.ddd.abc")
.tap("JavascriptParserTest", expr => {
if (!testParser.state.cdedddabc) testParser.state.cdedddabc = []; if (!testParser.state.cdedddabc) testParser.state.cdedddabc = [];
testParser.state.cdedddabc.push( testParser.state.cdedddabc.push(
testParser.parseString(expr.arguments[0]) testParser.parseString(expr.arguments[0])
); );
return true; return true;
}); });
testParser.hooks.expression.tap("fgh", "JavascriptParserTest", expr => { testParser.hooks.expression
.for("fgh")
.tap("JavascriptParserTest", expr => {
if (!testParser.state.fgh) testParser.state.fgh = []; if (!testParser.state.fgh) testParser.state.fgh = [];
testParser.state.fgh.push( testParser.state.fgh.push(
Array.from(testParser.scope.definitions.asSet()).join(" ") Array.from(testParser.scope.definitions.asSet()).join(" ")
); );
return true; return true;
}); });
testParser.hooks.expression.tap( testParser.hooks.expression
"fgh.sub", .for("fgh.sub")
"JavascriptParserTest", .tap("JavascriptParserTest", expr => {
expr => {
if (!testParser.state.fghsub) testParser.state.fghsub = []; if (!testParser.state.fghsub) testParser.state.fghsub = [];
testParser.state.fghsub.push( testParser.state.fghsub.push(
testParser.scope.inTry ? "try" : "notry" testParser.scope.inTry ? "try" : "notry"
); );
return true; return true;
} });
); testParser.hooks.expression
testParser.hooks.expression.tap( .for("ijk.sub")
"ijk.sub", .tap("JavascriptParserTest", expr => {
"JavascriptParserTest",
expr => {
if (!testParser.state.ijksub) testParser.state.ijksub = []; if (!testParser.state.ijksub) testParser.state.ijksub = [];
testParser.state.ijksub.push("test"); testParser.state.ijksub.push("test");
return true; return true;
} });
); testParser.hooks.expression
testParser.hooks.expression.tap( .for("memberExpr")
"memberExpr", .tap("JavascriptParserTest", expr => {
"JavascriptParserTest",
expr => {
if (!testParser.state.expressions) testParser.state.expressions = []; if (!testParser.state.expressions) testParser.state.expressions = [];
testParser.state.expressions.push(expr.name); testParser.state.expressions.push(expr.name);
return true; return true;
} });
);
testParser.hooks.new.tap("xyz", "JavascriptParserTest", expr => { testParser.hooks.new.tap("xyz", "JavascriptParserTest", expr => {
if (!testParser.state.xyz) testParser.state.xyz = []; if (!testParser.state.xyz) testParser.state.xyz = [];
testParser.state.xyz.push(testParser.parseString(expr.arguments[0])); testParser.state.xyz.push(testParser.parseString(expr.arguments[0]));
@ -367,21 +361,19 @@ describe("JavascriptParser", () => {
describe("expression evaluation", () => { describe("expression evaluation", () => {
function evaluateInParser(source) { function evaluateInParser(source) {
const parser = new JavascriptParser(); const parser = new JavascriptParser();
parser.hooks.call.tap("test", "JavascriptParserTest", expr => { parser.hooks.call.for("test").tap("JavascriptParserTest", expr => {
parser.state.result = parser.evaluateExpression(expr.arguments[0]); parser.state.result = parser.evaluateExpression(expr.arguments[0]);
}); });
parser.hooks.evaluateIdentifier.tap( parser.hooks.evaluateIdentifier
"aString", .for("aString")
"JavascriptParserTest", .tap("JavascriptParserTest", expr =>
expr =>
new BasicEvaluatedExpression() new BasicEvaluatedExpression()
.setString("aString") .setString("aString")
.setRange(expr.range) .setRange(expr.range)
); );
parser.hooks.evaluateIdentifier.tap( parser.hooks.evaluateIdentifier
"b.Number", .for("b.Number")
"JavascriptParserTest", .tap("JavascriptParserTest", expr =>
expr =>
new BasicEvaluatedExpression().setNumber(123).setRange(expr.range) new BasicEvaluatedExpression().setNumber(123).setRange(expr.range)
); );
return parser.parse("test(" + source + ");").result; return parser.parse("test(" + source + ");").result;
@ -615,7 +607,7 @@ describe("JavascriptParser", () => {
}; };
const parser = new JavascriptParser(); const parser = new JavascriptParser();
parser.hooks.call.tap("require", "JavascriptParserTest", expr => { parser.hooks.call.for("require").tap("JavascriptParserTest", expr => {
const param = parser.evaluateExpression(expr.arguments[0]); const param = parser.evaluateExpression(expr.arguments[0]);
parser.state.param = param.string; parser.state.param = param.string;
}); });

View File

@ -6,6 +6,15 @@ const fs = require("graceful-fs");
const webpack = require(".."); const webpack = require("..");
/**
* Escapes regular expression metacharacters
* @param {string} str String to quote
* @returns {string} Escaped string
*/
const quotemeta = str => {
return str.replace(/[-[\]\\/{}()*+?.^$|]/g, "\\$&");
};
const base = path.join(__dirname, "statsCases"); const base = path.join(__dirname, "statsCases");
const outputBase = path.join(__dirname, "js", "stats"); const outputBase = path.join(__dirname, "js", "stats");
const tests = fs const tests = fs
@ -129,24 +138,21 @@ describe("StatsTestCases", () => {
if (!hasColorSetting) { if (!hasColorSetting) {
actual = actual actual = actual
.replace(/\u001b\[[0-9;]*m/g, "") .replace(/\u001b\[[0-9;]*m/g, "")
.replace(/[0-9]+(\s?ms)/g, "X$1"); .replace(/[.0-9]+(\s?ms)/g, "X$1");
} else { } else {
actual = actual actual = actual
.replace(/\u001b\[1m\u001b\[([0-9;]*)m/g, "<CLR=$1,BOLD>") .replace(/\u001b\[1m\u001b\[([0-9;]*)m/g, "<CLR=$1,BOLD>")
.replace(/\u001b\[1m/g, "<CLR=BOLD>") .replace(/\u001b\[1m/g, "<CLR=BOLD>")
.replace(/\u001b\[39m\u001b\[22m/g, "</CLR>") .replace(/\u001b\[39m\u001b\[22m/g, "</CLR>")
.replace(/\u001b\[([0-9;]*)m/g, "<CLR=$1>") .replace(/\u001b\[([0-9;]*)m/g, "<CLR=$1>")
.replace(/[0-9]+(<\/CLR>)?(\s?ms)/g, "X$1$2"); .replace(/[.0-9]+(<\/CLR>)?(\s?ms)/g, "X$1$2");
} }
const testPath = path.join(base, testName); const testPath = path.join(base, testName);
const testPathPattern = testPath.replace(
/[-[\]\\/{}()*+?.^$|]/g,
"\\$&"
);
actual = actual actual = actual
.replace(/\r\n?/g, "\n") .replace(/\r\n?/g, "\n")
.replace(/[\t ]*Version:.+\n/g, "") .replace(/[\t ]*Version:.+\n/g, "")
.replace(new RegExp(testPathPattern, "g"), "Xdir/" + testName) .replace(new RegExp(quotemeta(testPath), "g"), "Xdir/" + testName)
.replace(/(\w)\\(\w)/g, "$1/$2")
.replace(/, additional resolving: Xms/g, ""); .replace(/, additional resolving: Xms/g, "");
expect(actual).toMatchSnapshot(); expect(actual).toMatchSnapshot();
done(); done();

View File

@ -193,7 +193,7 @@ describe("Validation", () => {
expect(msg).toMatchInlineSnapshot(` expect(msg).toMatchInlineSnapshot(`
"Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema. "Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
- configuration has an unknown property 'postcss'. These properties are valid: - configuration has an unknown property 'postcss'. These properties are valid:
object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry?, experiments?, externals?, loader?, mode?, module?, name?, node?, optimization?, output?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, serve?, stats?, target?, watch?, watchOptions? } object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry?, experiments?, externals?, infrastructureLogging?, loader?, mode?, module?, name?, node?, optimization?, output?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, serve?, stats?, target?, watch?, watchOptions? }
For typos: please correct them. For typos: please correct them.
For loader options: webpack >= v2.0.0 no longer allows custom properties in configuration. For loader options: webpack >= v2.0.0 no longer allows custom properties in configuration.
Loaders should be updated to allow passing options via loader options in module.rules. Loaders should be updated to allow passing options via loader options in module.rules.

View File

@ -1277,6 +1277,43 @@ Child 4 chunks:
[767] ./d.js 22 bytes {524} [built]" [767] ./d.js 22 bytes {524} [built]"
`; `;
exports[`StatsTestCases should print correct stats for logging 1`] = `
"Hash: <CLR=BOLD>17d1aced1f8edabe0aa9</CLR>
Time: <CLR=BOLD>X</CLR>ms
Built at: 1970-04-20 <CLR=BOLD>12:42:42</CLR>
<CLR=BOLD>Asset</CLR> <CLR=BOLD>Size</CLR> <CLR=BOLD>Chunks</CLR> <CLR=BOLD>Chunk Names</CLR>
<CLR=32,BOLD>main.js</CLR> 1.32 KiB {<CLR=33,BOLD>179</CLR>} <CLR=32,BOLD>[emitted]</CLR> main
Entrypoint <CLR=BOLD>main</CLR> = <CLR=32,BOLD>main.js</CLR>
[390] <CLR=BOLD>./index.js</CLR> 1 bytes {<CLR=33,BOLD>179</CLR>} <CLR=32,BOLD>[built]</CLR>
<CLR=BOLD>LOG from MyPlugin</CLR>
<i> <CLR=32,BOLD>Plugin is now active</CLR>
<+> <CLR=36,BOLD>Nested</CLR>
+ 3 hidden lines
<CLR=31,BOLD>DEBUG</CLR> <CLR=BOLD>LOG from ./node_modules/custom-loader/index.js ./node_modules/custom-loader/index.js!./index.js</CLR>
<e> <CLR=31,BOLD>An error</CLR>
| at Object.<anonymous>.module.exports (Xdir/logging/node_modules/custom-loader/index.js:5:9)
<w> <CLR=33,BOLD>A warning</CLR>
| at Object.<anonymous>.module.exports (Xdir/logging/node_modules/custom-loader/index.js:6:9)
<CLR=36,BOLD>Unimportant</CLR>
<i> <CLR=32,BOLD>Info message</CLR>
<CLR=BOLD>Just log</CLR>
Just debug
<t> <CLR=35,BOLD>Measure: Xms</CLR>
<CLR=36,BOLD>Nested</CLR>
<CLR=BOLD>Log inside collapsed group</CLR>
Trace
| at Object.<anonymous>.module.exports (Xdir/logging/node_modules/custom-loader/index.js:15:9)
<t> <CLR=35,BOLD>Measure: Xms</CLR>
-------
<CLR=BOLD>After clear</CLR>
<CLR=31,BOLD>DEBUG</CLR> <CLR=BOLD>LOG from ./node_modules/custom-loader/index.js Named Logger ./node_modules/custom-loader/index.js!./index.js</CLR>
Message with named logger
"
`;
exports[`StatsTestCases should print correct stats for max-modules 1`] = ` exports[`StatsTestCases should print correct stats for max-modules 1`] = `
"Hash: 8a3d2df87a4f01705c82 "Hash: 8a3d2df87a4f01705c82
Time: Xms Time: Xms
@ -2062,20 +2099,48 @@ webpack/runtime/jsonp chunk loading 3.36 KiB {179} [runtime]
[used exports unknown] [used exports unknown]
webpack/runtime/publicPath 27 bytes {179} [runtime] webpack/runtime/publicPath 27 bytes {179} [runtime]
[no exports] [no exports]
[used exports unknown]" [used exports unknown]
LOG from MyPlugin
Group
<e> Error
<w> Warning
<i> Info
Log
<+> Collaped group
+ 3 hidden lines
"
`; `;
exports[`StatsTestCases should print correct stats for preset-errors-only 1`] = `""`; exports[`StatsTestCases should print correct stats for preset-errors-only 1`] = `""`;
exports[`StatsTestCases should print correct stats for preset-errors-only-error 1`] = ` exports[`StatsTestCases should print correct stats for preset-errors-only-error 1`] = `
"ERROR in ./index.js 1:0-25 "LOG from MyPlugin
<e> Error
+ 9 hidden lines
ERROR in ./index.js 1:0-25
Module not found: Error: Can't resolve 'does-not-exist' in 'Xdir/preset-errors-only-error' Module not found: Error: Can't resolve 'does-not-exist' in 'Xdir/preset-errors-only-error'
" "
`; `;
exports[`StatsTestCases should print correct stats for preset-errors-warnings 1`] = `""`; exports[`StatsTestCases should print correct stats for preset-errors-warnings 1`] = `
"LOG from MyPlugin
<e> Error
<w> Warning
+ 8 hidden lines
"
`;
exports[`StatsTestCases should print correct stats for preset-minimal 1`] = `" 10 modules"`; exports[`StatsTestCases should print correct stats for preset-minimal 1`] = `
" 10 modules
LOG from MyPlugin
<e> Error
<w> Warning
+ 8 hidden lines
"
`;
exports[`StatsTestCases should print correct stats for preset-minimal-simple 1`] = `" 1 module"`; exports[`StatsTestCases should print correct stats for preset-minimal-simple 1`] = `" 1 module"`;
@ -2109,7 +2174,14 @@ Entrypoint main = main.js
[767] ./d.js 22 bytes {524} [built] [767] ./d.js 22 bytes {524} [built]
[847] ./a.js 22 bytes {179} [built] [847] ./a.js 22 bytes {179} [built]
[996] ./b.js 22 bytes {996} [built] [996] ./b.js 22 bytes {996} [built]
+ 4 hidden modules" + 4 hidden modules
LOG from MyPlugin
<e> Error
<w> Warning
<i> Info
+ 7 hidden lines
"
`; `;
exports[`StatsTestCases should print correct stats for preset-normal-performance 1`] = ` exports[`StatsTestCases should print correct stats for preset-normal-performance 1`] = `
@ -2230,7 +2302,18 @@ chunk {996} 996.js 22 bytes <{179}> [rendered]
[996] ./b.js 22 bytes {996} [depth 1] [built] [996] ./b.js 22 bytes {996} [depth 1] [built]
ModuleConcatenation bailout: Module is not an ECMAScript module ModuleConcatenation bailout: Module is not an ECMAScript module
amd require ./b [10] ./index.js 2:0-16 amd require ./b [10] ./index.js 2:0-16
[10] Xms -> Xms (resolving: Xms, restoring: Xms, integration: Xms, building: Xms, storing: Xms)" [10] Xms -> Xms (resolving: Xms, restoring: Xms, integration: Xms, building: Xms, storing: Xms)
LOG from MyPlugin
Group
<e> Error
<w> Warning
<i> Info
Log
Collaped group
Log inside collapsed group
+ 1 hidden lines
"
`; `;
exports[`StatsTestCases should print correct stats for resolve-plugin-context 1`] = ` exports[`StatsTestCases should print correct stats for resolve-plugin-context 1`] = `

View File

View File

@ -0,0 +1,21 @@
/* eslint-disable node/no-unsupported-features/node-builtins */
module.exports = function(source) {
const logger = this.getLogger ? this.getLogger() : console;
logger.time("Measure");
logger.error("An error");
logger.warn("A %s", "warning");
logger.group("Unimportant");
logger.info("Info message");
logger.log("Just log");
logger.debug("Just debug");
logger.timeLog("Measure");
logger.groupCollapsed("Nested");
logger.log("Log inside collapsed group");
logger.groupEnd("Nested");
logger.trace();
logger.timeEnd("Measure");
logger.clear();
logger.log("After clear");
this.getLogger("Named Logger").debug("Message with named logger");
return source;
};

View File

@ -0,0 +1,36 @@
class MyPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("MyPlugin", compilation => {
const logger = compilation.getLogger("MyPlugin");
logger.info("Plugin is now active");
logger.debug("Debug message should not be visible");
logger.groupCollapsed("Nested");
logger.log("Log inside collapsed group");
logger.groupEnd("Nested");
const otherLogger = compilation.getLogger("MyOtherPlugin");
otherLogger.debug("debug message only");
});
}
}
module.exports = {
mode: "production",
entry: "./index",
performance: false,
module: {
rules: [
{
test: /index\.js$/,
use: "custom-loader"
}
]
},
plugins: [new MyPlugin()],
stats: {
colors: true,
logging: true,
loggingDebug: "custom-loader",
loggingTrace: true
}
};

View File

@ -1,5 +1,24 @@
class MyPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("MyPlugin", compilation => {
const logger = compilation.getLogger("MyPlugin");
logger.group("Group");
logger.error("Error");
logger.warn("Warning");
logger.info("Info");
logger.log("Log");
logger.debug("Debug");
logger.groupCollapsed("Collaped group");
logger.log("Log inside collapsed group");
logger.groupEnd();
logger.groupEnd();
});
}
}
module.exports = { module.exports = {
mode: "production", mode: "production",
entry: "./index", entry: "./index",
stats: "detailed" stats: "detailed",
plugins: [new MyPlugin()]
}; };

View File

@ -1,5 +1,24 @@
class MyPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("MyPlugin", compilation => {
const logger = compilation.getLogger("MyPlugin");
logger.group("Group");
logger.error("Error");
logger.warn("Warning");
logger.info("Info");
logger.log("Log");
logger.debug("Debug");
logger.groupCollapsed("Collaped group");
logger.log("Log inside collapsed group");
logger.groupEnd();
logger.groupEnd();
});
}
}
module.exports = { module.exports = {
mode: "production", mode: "production",
entry: "./index", entry: "./index",
stats: "errors-only" stats: "errors-only",
plugins: [new MyPlugin()]
}; };

View File

@ -1,5 +1,24 @@
class MyPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("MyPlugin", compilation => {
const logger = compilation.getLogger("MyPlugin");
logger.group("Group");
logger.error("Error");
logger.warn("Warning");
logger.info("Info");
logger.log("Log");
logger.debug("Debug");
logger.groupCollapsed("Collaped group");
logger.log("Log inside collapsed group");
logger.groupEnd();
logger.groupEnd();
});
}
}
module.exports = { module.exports = {
mode: "production", mode: "production",
entry: "./index", entry: "./index",
stats: "errors-warnings" stats: "errors-warnings",
plugins: [new MyPlugin()]
}; };

View File

@ -1,5 +1,24 @@
class MyPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("MyPlugin", compilation => {
const logger = compilation.getLogger("MyPlugin");
logger.group("Group");
logger.error("Error");
logger.warn("Warning");
logger.info("Info");
logger.log("Log");
logger.debug("Debug");
logger.groupCollapsed("Collaped group");
logger.log("Log inside collapsed group");
logger.groupEnd();
logger.groupEnd();
});
}
}
module.exports = { module.exports = {
mode: "production", mode: "production",
entry: "./index", entry: "./index",
stats: "minimal" stats: "minimal",
plugins: [new MyPlugin()]
}; };

View File

@ -1,5 +1,24 @@
class MyPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("MyPlugin", compilation => {
const logger = compilation.getLogger("MyPlugin");
logger.group("Group");
logger.error("Error");
logger.warn("Warning");
logger.info("Info");
logger.log("Log");
logger.debug("Debug");
logger.groupCollapsed("Collaped group");
logger.log("Log inside collapsed group");
logger.groupEnd();
logger.groupEnd();
});
}
}
module.exports = { module.exports = {
mode: "production", mode: "production",
entry: "./index", entry: "./index",
stats: false stats: false,
plugins: [new MyPlugin()]
}; };

View File

@ -1,5 +1,24 @@
class MyPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("MyPlugin", compilation => {
const logger = compilation.getLogger("MyPlugin");
logger.group("Group");
logger.error("Error");
logger.warn("Warning");
logger.info("Info");
logger.log("Log");
logger.debug("Debug");
logger.groupCollapsed("Collaped group");
logger.log("Log inside collapsed group");
logger.groupEnd();
logger.groupEnd();
});
}
}
module.exports = { module.exports = {
mode: "production", mode: "production",
entry: "./index", entry: "./index",
stats: "normal" stats: "normal",
plugins: [new MyPlugin()]
}; };

View File

@ -1,6 +1,25 @@
class MyPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("MyPlugin", compilation => {
const logger = compilation.getLogger("MyPlugin");
logger.group("Group");
logger.error("Error");
logger.warn("Warning");
logger.info("Info");
logger.log("Log");
logger.debug("Debug");
logger.groupCollapsed("Collaped group");
logger.log("Log inside collapsed group");
logger.groupEnd();
logger.groupEnd();
});
}
}
module.exports = { module.exports = {
mode: "production", mode: "production",
entry: "./index", entry: "./index",
profile: true, profile: true,
stats: "verbose" stats: "verbose",
plugins: [new MyPlugin()]
}; };

View File

@ -373,9 +373,9 @@
integrity sha512-MeatbbUsZ80BEsKPXby6pUZjUM9ZuHIpWElN0siopih3fvnlpX2O9L6D5+dzDIb36lf9tM/8U4PVdLQ+L4qr4A== integrity sha512-MeatbbUsZ80BEsKPXby6pUZjUM9ZuHIpWElN0siopih3fvnlpX2O9L6D5+dzDIb36lf9tM/8U4PVdLQ+L4qr4A==
"@types/node@^10.12.21": "@types/node@^10.12.21":
version "10.14.12" version "10.14.13"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.12.tgz#0eec3155a46e6c4db1f27c3e588a205f767d622f" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.13.tgz#ac786d623860adf39a3f51d629480aacd6a6eec7"
integrity sha512-QcAKpaO6nhHLlxWBvpc4WeLrTvPqlHOvaj0s5GriKkA1zq+bsFBPpfYCvQhLqLgYlIko8A9YrPdaMHCo5mBcpg== integrity sha512-yN/FNNW1UYsRR1wwAoyOwqvDuLDtVXnaJTZ898XIw/Q5cCaeVAlVwvsmXLX5PuiScBYwZsZU4JYSHB3TvfdwvQ==
"@types/prettier@^1.16.1": "@types/prettier@^1.16.1":
version "1.16.1" version "1.16.1"
@ -609,9 +609,9 @@ acorn@^5.5.3:
integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
acorn@^6.0.1, acorn@^6.0.7, acorn@^6.2.0: acorn@^6.0.1, acorn@^6.0.7, acorn@^6.2.0:
version "6.2.0" version "6.2.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.0.tgz#67f0da2fc339d6cfb5d6fb244fd449f33cd8bbe3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.1.tgz#3ed8422d6dec09e6121cc7a843ca86a330a86b51"
integrity sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw== integrity sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==
ajv-errors@^1.0.0: ajv-errors@^1.0.0:
version "1.0.1" version "1.0.1"
@ -1321,10 +1321,10 @@ commander@^2.14.1, commander@^2.19.0, commander@^2.9.0, commander@~2.20.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
comment-parser@^0.5.5: comment-parser@^0.6.0:
version "0.5.5" version "0.6.1"
resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-0.5.5.tgz#c2584cae7c2f0afc773e96b2ee98f8c10cbd693d" resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-0.6.1.tgz#88040c7c0a57c62e64962c3e888518620a42e7c9"
integrity sha512-oB3TinFT+PV3p8UwDQt71+HkG03+zwPwikDlKU6ZDmql6QX2zFlQ+G0GGSDqyJhdZi4PSlzFBm+YJ+ebOX3Vgw== integrity sha512-Putzd7Ilyvknmb1KxGf5el9uw0sPx9gEVnDrm8tlvXGN1i8Uaa2VBxB32hUhfzTlrEhhxNQ+pKq4ZNe8wNxjmw==
commondir@^1.0.1: commondir@^1.0.1:
version "1.0.1" version "1.0.1"
@ -1841,16 +1841,16 @@ eslint-plugin-es@^1.3.1:
regexpp "^2.0.1" regexpp "^2.0.1"
eslint-plugin-jest@^22.2.2: eslint-plugin-jest@^22.2.2:
version "22.8.0" version "22.13.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-22.8.0.tgz#242ef5459e8da25d2c41438e95eb546e03d7fae1" resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-22.13.0.tgz#d7d134c6e3c2f67cc50f5fa89a329db579d28428"
integrity sha512-2VftZMfILmlhL3VMq5ptHRIuyyXb3ShDEDb1J1UjvWNzm4l+UK/YmwNuTuJcM0gv8pJuOfiR/8ZptJ8Ou68pFw== integrity sha512-bIr8LL7buUXS8Pk69SFgaDKgyvPQkDu6i8ko0lP54uccszlo4EOwtstDXOZl5Af3JwudbECxRUbCpL/2cKDkkg==
eslint-plugin-jsdoc@^15.3.2: eslint-plugin-jsdoc@^15.3.2:
version "15.5.2" version "15.5.3"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-15.5.2.tgz#89768320c64ec2f30d12209e1926c4decca0568a" resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-15.5.3.tgz#44e408e3bf2f60f3ad18dc829f9b9a1e34f33154"
integrity sha512-5s39RYGaqugWVoOfc6pAwj9yeNh7mclygBWTyYVJX+sGiNchwCtgHbn2AjeonOw0g168CPI3itiXetHj2Yo8gg== integrity sha512-lw8wYa1UFV53JLoqKOQR8YBkKlE/aguR+HGyytL9VKsVvm83DK8ReYnNNDRKik3MF661cGuaUuGfIEcdqg9l4A==
dependencies: dependencies:
comment-parser "^0.5.5" comment-parser "^0.6.0"
debug "^4.1.1" debug "^4.1.1"
flat-map-polyfill "^0.3.8" flat-map-polyfill "^0.3.8"
jsdoctypeparser "5.0.1" jsdoctypeparser "5.0.1"
@ -3835,9 +3835,9 @@ lodash.sortby@^4.7.0:
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.4: lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.4:
version "4.17.14" version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw== integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
log-driver@^1.2.7: log-driver@^1.2.7:
version "1.2.7" version "1.2.7"
@ -5500,9 +5500,9 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
simple-git@^1.65.0, simple-git@^1.85.0: simple-git@^1.65.0, simple-git@^1.85.0:
version "1.121.0" version "1.122.0"
resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.121.0.tgz#4bdf0828cd1b0bb3cb7ed9bead2771982ef5876a" resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.122.0.tgz#33b2d3a760aa02df470c79fbab5413d4f4e68945"
integrity sha512-LyYri/nuAX8+cx9nZw38mWO6oHNi//CmiPlkBL7aVjZIsdldve7eeDwXu9L4wP/74MpNHucXkXc/BOuIQShhPg== integrity sha512-plTwhnkIHrw2TFMJbJH/mKwWGgFbj03V9wcfBKa4FsuvgJbpwdlSJnlvkIQWDV1CVLaf2Gl6zSNeRRnxBRhX1g==
dependencies: dependencies:
debug "^4.0.1" debug "^4.0.1"