Add compiler typings

This commit is contained in:
Florent Cailhol 2018-12-10 11:34:59 +01:00
parent 6913e3bbb1
commit e06b4853d6
11 changed files with 316 additions and 102 deletions

View File

@ -396,26 +396,7 @@ export interface WebpackOptions {
/**
* Options for the watcher
*/
watchOptions?: {
/**
* Delay the rebuilt after the first change. Value is a time in ms.
*/
aggregateTimeout?: number;
/**
* Ignore some files from watching
*/
ignored?: {
[k: string]: any;
};
/**
* Enable polling mode for watching
*/
poll?: boolean | number;
/**
* Stop watching when stdin stream has ended
*/
stdin?: boolean;
};
watchOptions?: WatchOptions;
}
/**
* This interface was referenced by `WebpackOptions`'s JSON-Schema
@ -1421,3 +1402,27 @@ export interface StatsOptions {
*/
warningsFilter?: FilterTypes;
}
/**
* This interface was referenced by `WebpackOptions`'s JSON-Schema
* via the `definition` "WatchOptions".
*/
export interface WatchOptions {
/**
* Delay the rebuilt after the first change. Value is a time in ms.
*/
aggregateTimeout?: number;
/**
* Ignore some files from watching
*/
ignored?: {
[k: string]: any;
};
/**
* Enable polling mode for watching
*/
poll?: boolean | number;
/**
* Stop watching when stdin stream has ended
*/
stdin?: boolean;
}

View File

@ -68,13 +68,32 @@ const { arrayToSetDeprecation } = require("./util/deprecation");
/** @typedef {import("./dependencies/EntryDependency")} EntryDependency */
/** @typedef {import("./util/createHash").Hash} Hash */
// TODO use @callback
/** @typedef {{[assetName: string]: Source}} CompilationAssets */
/** @typedef {(err?: WebpackError|null, result?: Module) => void } ModuleCallback */
/** @typedef {(err?: Error|null) => void} Callback */
/** @typedef {(d: Dependency) => any} DepBlockVarDependenciesCallback */
/**
* @callback Callback
* @param {WebpackError=} err
* @returns {void}
*/
/**
* @callback ModuleCallback
* @param {WebpackError=} err
* @param {Module=} result
* @returns {void}
*/
/**
* @callback DepBlockVarDependenciesCallback
* @param {Dependency} dependency
* @returns {any}
*/
/**
* @typedef {Object} Plugin
* @property {() => void} apply
*/
/** @typedef {new (...args: any[]) => Dependency} DepConstructor */
/** @typedef {{apply: () => void}} Plugin */
/** @typedef {Record<string, Source>} CompilationAssets */
/**
* @typedef {Object} ModuleFactoryCreateDataContextInfo
@ -536,12 +555,6 @@ class Compilation {
return new Stats(this);
}
/**
* @typedef {Object} AddModuleResult
* @property {Module} module the added or existing module
* @property {boolean} issuer was this the first request for this module
*/
/**
* @param {Module} module module to be added that was created
* @param {ModuleCallback} callback returns the module in the compilation,
@ -631,7 +644,7 @@ class Compilation {
*
* @param {Module} module module to be built
* @param {ModuleCallback} callback the callback
* @returns {TODO} returns the callback function with results
* @returns {void}
*/
_buildModule(module, callback) {
const currentProfile = this.profile
@ -1116,7 +1129,7 @@ class Compilation {
}
/**
* @param {Callback} callback signals when the seal method is finishes
* @param {Callback} callback signals when the call finishes
* @returns {void}
*/
seal(callback) {
@ -2294,6 +2307,10 @@ class Compilation {
}
}
/**
* @param {Callback} callback signals when the call finishes
* @returns {void}
*/
createChunkAssets(callback) {
const outputOptions = this.outputOptions;
const cachedSourceMap = new WeakMap();

View File

@ -28,8 +28,13 @@ const Watching = require("./Watching");
const { makePathsRelative } = require("./util/identifier");
/** @typedef {import("../declarations/WebpackOptions").Entry} Entry */
/** @typedef {import("../declarations/WebpackOptions").OutputOptions} OutputOptions */
/** @typedef {import("../declarations/WebpackOptions").WatchOptions} WatchOptions */
/** @typedef {import("../declarations/WebpackOptions").WebpackOptions} WebpackOptions */
/** @typedef {import("../declarations/WebpackOptions").WebpackPluginInstance} WebpackPluginInstance */
/** @typedef {import("./Chunk")} Chunk */
/** @typedef {import("./FileSystemInfo").FileSystemInfoEntry} FileSystemInfoEntry */
/** @typedef {import("./Stats")} Stats */
/**
* @typedef {Object} CompilationParams
@ -38,7 +43,24 @@ const { makePathsRelative } = require("./util/identifier");
* @property {Set<string>} compilationDependencies
*/
/**
* @template T
* @callback Callback
* @param {Error=} err
* @param {T=} result
*/
/**
* @callback RunAsChildCallback
* @param {Error=} err
* @param {Chunk[]=} entries
* @param {Compilation=} compilation
*/
class Compiler {
/**
* @param {string} context the compilation path
*/
constructor(context) {
this.hooks = Object.freeze({
/** @type {SyncBailHook<Compilation>} */
@ -142,16 +164,29 @@ class Compiler {
this.watchMode = false;
}
/**
* @param {WatchOptions} watchOptions the watcher's options
* @param {Callback<Stats>} handler signals when the call finishes
* @returns {Watching} a compiler watcher
*/
watch(watchOptions, handler) {
if (this.running) return handler(new ConcurrentCompilationError());
if (this.running) {
return handler(new ConcurrentCompilationError());
}
this.running = true;
this.watchMode = true;
return new Watching(this, watchOptions, handler);
}
/**
* @param {Callback<Stats>} callback signals when the call finishes
* @returns {void}
*/
run(callback) {
if (this.running) return callback(new ConcurrentCompilationError());
if (this.running) {
return callback(new ConcurrentCompilationError());
}
const finalCallback = (err, stats) => {
this.cache.beginIdle();
@ -231,6 +266,10 @@ class Compiler {
});
}
/**
* @param {RunAsChildCallback} callback signals when the call finishes
* @returns {void}
*/
runAsChild(callback) {
this.compile((err, compilation) => {
if (err) return callback(err);
@ -257,6 +296,11 @@ class Compiler {
}
}
/**
* @param {Compilation} compilation the compilation
* @param {Callback<void>} callback signals when the assets are emitted
* @returns {void}
*/
emitAssets(compilation, callback) {
let outputPath;
@ -322,6 +366,10 @@ class Compiler {
});
}
/**
* @param {Callback<void>} callback signals when the call finishes
* @returns {void}
*/
emitRecords(callback) {
if (!this.recordsOutputPath) return callback();
const idx1 = this.recordsOutputPath.lastIndexOf("/");
@ -350,6 +398,10 @@ class Compiler {
});
}
/**
* @param {Callback<void>} callback signals when the call finishes
* @returns {void}
*/
readRecords(callback) {
if (!this.recordsInputPath) {
this.records = {};
@ -375,6 +427,14 @@ class Compiler {
});
}
/**
* @param {Compilation} compilation the compilation
* @param {string} compilerName the compiler's name
* @param {number} compilerIndex the compiler's index
* @param {OutputOptions} outputOptions the output options
* @param {WebpackPluginInstance[]} plugins the plugins to apply
* @returns {Compiler} a child compiler
*/
createChildCompiler(
compilation,
compilerName,
@ -454,6 +514,10 @@ class Compiler {
return new Compilation(this);
}
/**
* @param {CompilationParams} params the compilation parameters
* @returns {Compilation} the created compilation
*/
newCompilation(params) {
const compilation = this.createCompilation();
compilation.name = this.name;
@ -489,6 +553,10 @@ class Compiler {
return params;
}
/**
* @param {Callback<Compilation>} callback signals when the compilation finishes
* @returns {void}
*/
compile(callback) {
const params = this.newCompilationParams();
this.hooks.beforeCompile.callAsync(params, err => {
@ -516,6 +584,10 @@ class Compiler {
});
}
/**
* @param {Callback<void>} callback signals when the compiler closes
* @returns {void}
*/
close(callback) {
this.cache.shutdown(callback);
}

View File

@ -11,7 +11,9 @@ const ConcurrentCompilationError = require("./ConcurrentCompilationError");
const MultiStats = require("./MultiStats");
const MultiWatching = require("./MultiWatching");
/** @typedef {import("../declarations/WebpackOptions").WatchOptions} WatchOptions */
/** @typedef {import("./Compiler")} Compiler */
/** @typedef {import("./Stats")} Stats */
/** @typedef {number} CompilerStatus */
@ -19,33 +21,52 @@ const STATUS_PENDING = 0;
const STATUS_DONE = 1;
const STATUS_NEW = 2;
/**
* @template T
* @callback Callback
* @param {Error=} err
* @param {T=} result
*/
/**
* @callback RunWithDependenciesHandler
* @param {Compiler} compiler
* @param {Callback<MultiStats>} callback
*/
module.exports = class MultiCompiler {
/**
* @param {Compiler[]} compilers child compilers
* @param {Compiler[] | Record<string, Compiler>} compilers child compilers
*/
constructor(compilers) {
this.hooks = Object.freeze({
done: new SyncHook(["stats"]),
invalid: new MultiHook(compilers.map(c => c.hooks.invalid)),
run: new MultiHook(compilers.map(c => c.hooks.run)),
watchClose: new SyncHook([]),
watchRun: new MultiHook(compilers.map(c => c.hooks.watchRun))
});
if (!Array.isArray(compilers)) {
compilers = Object.keys(compilers).map(name => {
compilers[name].name = name;
return compilers[name];
});
}
this.hooks = Object.freeze({
/** @type {SyncHook<MultiStats>} */
done: new SyncHook(["stats"]),
invalid: new MultiHook(compilers.map(c => c.hooks.invalid)),
run: new MultiHook(compilers.map(c => c.hooks.run)),
/** @type {SyncHook} */
watchClose: new SyncHook([]),
watchRun: new MultiHook(compilers.map(c => c.hooks.watchRun))
});
this.compilers = compilers;
/** @type {WeakMap<Compiler, string[]>} */
this.dependencies = new WeakMap();
this.running = false;
/** @type {Stats[]} */
const compilerStats = this.compilers.map(() => null);
let doneCompilers = 0;
let compilerStats = [];
let index = 0;
for (const compiler of this.compilers) {
for (let index = 0; index < this.compilers.length; index++) {
const compiler = this.compilers[index];
const compilerIndex = index;
let compilerDone = false;
const compilerIndex = index++;
// eslint-disable-next-line no-loop-func
compiler.hooks.done.tap("MultiCompiler", stats => {
if (!compilerDone) {
@ -65,7 +86,6 @@ module.exports = class MultiCompiler {
}
});
}
this.running = false;
}
get outputPath() {
@ -112,8 +132,14 @@ module.exports = class MultiCompiler {
this.dependencies.set(compiler, dependencies);
}
/**
* @param {Callback<MultiStats>} callback signals when the validation is complete
* @returns {boolean} true if the dependencies are valid
*/
validateDependencies(callback) {
/** @type {Set<{source: Compiler, target: Compiler}>} */
const edges = new Set();
/** @type {string[]} */
const missing = [];
const targetFound = compiler => {
for (const edge of edges) {
@ -174,6 +200,12 @@ module.exports = class MultiCompiler {
return true;
}
/**
* @param {Compiler[]} compilers the child compilers
* @param {RunWithDependenciesHandler} fn a handler to run for each compiler
* @param {Callback<MultiStats>} callback the compiler's handler
* @returns {void}
*/
runWithDependencies(compilers, fn, callback) {
const fulfilledNames = new Set();
let remainingCompilers = compilers;
@ -211,6 +243,11 @@ module.exports = class MultiCompiler {
runCompilers(callback);
}
/**
* @param {WatchOptions[]} watchOptions the watcher's options
* @param {Callback<MultiStats>} handler signals when the call finishes
* @returns {MultiWatching} a compiler watcher
*/
watch(watchOptions, handler) {
if (this.running) {
return handler(new ConcurrentCompilationError());
@ -264,6 +301,10 @@ module.exports = class MultiCompiler {
return new MultiWatching(watchings, this);
}
/**
* @param {Callback<MultiStats>} callback signals when the call finishes
* @returns {void}
*/
run(callback) {
if (this.running) {
return callback(new ConcurrentCompilationError());
@ -310,6 +351,10 @@ module.exports = class MultiCompiler {
}
}
/**
* @param {Callback<void>} callback signals when the compiler closes
* @returns {void}
*/
close(callback) {
asyncLib.each(
this.compilers,

View File

@ -11,21 +11,26 @@ const optionOrFallback = (optionValue, fallbackValue) =>
optionValue !== undefined ? optionValue : fallbackValue;
class MultiStats {
/**
* @param {Stats[]} stats the child stats
*/
constructor(stats) {
this.stats = stats;
this.hash = stats.map(stat => stat.hash).join("");
}
/**
* @returns {boolean} true if a child compilation encountered an error
*/
hasErrors() {
return this.stats
.map(stat => stat.hasErrors())
.reduce((a, b) => a || b, false);
return this.stats.some(stat => stat.hasErrors());
}
/**
* @returns {boolean} true if a child compilation had a warning
*/
hasWarnings() {
return this.stats
.map(stat => stat.hasWarnings())
.reduce((a, b) => a || b, false);
return this.stats.some(stat => stat.hasWarnings());
}
toJson(options, forToString) {
@ -83,7 +88,6 @@ class MultiStats {
}
const useColors = optionOrFallback(options.colors, false);
const obj = this.toJson(options, true);
return Stats.jsonToString(obj, useColors);

View File

@ -7,7 +7,21 @@
const asyncLib = require("neo-async");
/** @typedef {import("./MultiCompiler")} MultiCompiler */
/** @typedef {import("./Watching")} Watching */
/**
* @template T
* @callback Callback
* @param {Error=} err
* @param {T=} result
*/
class MultiWatching {
/**
* @param {Watching[]} watchings child compilers' watchers
* @param {MultiCompiler} compiler the compiler
*/
constructor(watchings, compiler) {
this.watchings = watchings;
this.compiler = compiler;
@ -19,6 +33,10 @@ class MultiWatching {
}
}
/**
* @param {Callback<void>} callback signals when the watcher is closed
* @returns {void}
*/
close(callback) {
asyncLib.forEach(
this.watchings,

View File

@ -52,6 +52,18 @@ const sortOrderRegular = field => {
return true;
};
/**
*
* @param {string} filePath the file path
* @returns {string} the formatted file path
*/
const formatFilePath = filePath => {
const OPTIONS_REGEXP = /^(\s|\S)*!/;
return filePath.includes("!")
? `${filePath.replace(OPTIONS_REGEXP, "")} (${filePath})`
: `${filePath}`;
};
class Stats {
/**
* @param {Compilation} compilation webpack compilation
@ -93,13 +105,9 @@ class Stats {
});
}
formatFilePath(filePath) {
const OPTIONS_REGEXP = /^(\s|\S)*!/;
return filePath.includes("!")
? `${filePath.replace(OPTIONS_REGEXP, "")} (${filePath})`
: `${filePath}`;
}
/**
* @returns {boolean} true if the compilation encountered an error
*/
hasWarnings() {
return (
this.compilation.warnings.length > 0 ||
@ -107,6 +115,9 @@ class Stats {
);
}
/**
* @returns {boolean} true if the compilation had a warning
*/
hasErrors() {
return (
this.compilation.errors.length > 0 ||
@ -365,9 +376,7 @@ class Stats {
e.module.readableIdentifier &&
typeof e.module.readableIdentifier === "function"
) {
text += this.formatFilePath(
e.module.readableIdentifier(requestShortener)
);
text += formatFilePath(e.module.readableIdentifier(requestShortener));
if (typeof e.loc === "object") {
const locInfo = formatLocation(e.loc);
if (locInfo) text += ` ${locInfo}`;
@ -387,7 +396,7 @@ class Stats {
while (current) {
const origin = moduleGraph.getIssuer(current);
if (!origin) break;
text += `\n @ ${this.formatFilePath(
text += `\n @ ${formatFilePath(
origin.readableIdentifier(requestShortener)
)}`;
const connections = moduleGraph.getIncomingConnections(current);

View File

@ -7,7 +7,17 @@
const Stats = require("./Stats");
/** @typedef {import("../declarations/WebpackOptions").WatchOptions} WatchOptions */
/** @typedef {import("./Compilation")} Compilation */
/** @typedef {import("./Compiler")} Compiler */
/** @typedef {import("./Stats")} Stats */
/**
* @template T
* @callback Callback
* @param {Error=} err
* @param {T=} result
*/
// TODO refactor watchpack to report timestamps in the correct format
const toFileSystemInfoEntryMap = timestamps => {
@ -21,13 +31,14 @@ const toFileSystemInfoEntryMap = timestamps => {
class Watching {
/**
* @param {Compiler} compiler the compiler
* @param {TODO} watchOptions options
* @param {TODO} handler TODO
* @param {WatchOptions} watchOptions options
* @param {Callback<Stats>} handler completion handler
*/
constructor(compiler, watchOptions, handler) {
this.startTime = null;
this.invalid = false;
this.handler = handler;
/** @type {Callback<void>[]} */
this.callbacks = [];
this.closed = false;
if (typeof watchOptions === "number") {
@ -98,6 +109,10 @@ class Watching {
});
}
/**
* @param {Compilation} compilation the compilation
* @returns {Stats} the compilation stats
*/
_getStats(compilation) {
const stats = new Stats(compilation);
stats.startTime = this.startTime;
@ -105,6 +120,11 @@ class Watching {
return stats;
}
/**
* @param {Error=} err an optional error
* @param {Compilation=} compilation the compilation
* @returns {void}
*/
_done(err, compilation) {
this.running = false;
if (this.invalid) return this._go();
@ -167,6 +187,10 @@ class Watching {
);
}
/**
* @param {Callback<void>=} callback signals when the build is invalidated
* @returns {void}
*/
invalidate(callback) {
if (callback) {
this.callbacks.push(callback);
@ -179,7 +203,7 @@ class Watching {
this.watcher.getContextTimestamps()
);
}
return this._invalidate();
this._invalidate();
}
_invalidate() {
@ -190,12 +214,15 @@ class Watching {
}
if (this.running) {
this.invalid = true;
return false;
} else {
this._go();
}
}
/**
* @param {Callback<void>} callback signals when the watcher is closed
* @returns {void}
*/
close(callback) {
const finalCallback = () => {
this.compiler.running = false;

View File

@ -7,7 +7,12 @@
const { SyncHook, AsyncSeriesHook } = require("tapable");
/** @template R @typedef {(err?: Error|null, result?: R) => void} Callback<T> */
/**
* @template T
* @callback Callback<T>
* @param {Error=} err
* @param {T=} result
*/
/**
* @template T

View File

@ -15,12 +15,14 @@ const NodeEnvironmentPlugin = require("./node/NodeEnvironmentPlugin");
const validateSchema = require("./validateSchema");
/** @typedef {import("../declarations/WebpackOptions").WebpackOptions} WebpackOptions */
/** @typedef {import("./MultiStats")} MultiStats */
/** @typedef {import("./Stats")} Stats */
/**
* @callback WebpackCallback
* @template T
* @callback Callback
* @param {Error=} err
* @param {Stats=} stats
* @param {T=} stats
* @returns {void}
*/
@ -68,7 +70,7 @@ const createCompiler = options => {
/**
* @param {WebpackOptions | WebpackOptions[]} options options object
* @param {WebpackCallback=} callback callback
* @param {Callback<Stats> | Callback<MultiStats>=} callback callback
* @returns {Compiler | MultiCompiler} the compiler object
*/
const webpack = (options, callback) => {
@ -76,6 +78,7 @@ const webpack = (options, callback) => {
if (validationErrors.length) {
throw new WebpackOptionsValidationError(validationErrors);
}
/** @type {TODO} */
let compiler;
let watch = false;
let watchOptions;
@ -94,6 +97,8 @@ const webpack = (options, callback) => {
} else {
compiler.run((err, stats) => {
compiler.close(err2 => {
// @ts-ignore
// TODO fix the typings
callback(err || err2, stats);
});
});

View File

@ -1933,6 +1933,36 @@
}
}
},
"WatchOptions": {
"type": "object",
"additionalProperties": false,
"properties": {
"aggregateTimeout": {
"description": "Delay the rebuilt after the first change. Value is a time in ms.",
"type": "number"
},
"ignored": {
"description": "Ignore some files from watching"
},
"poll": {
"description": "Enable polling mode for watching",
"anyOf": [
{
"description": "`true`: use polling.",
"type": "boolean"
},
{
"description": "`number`: use polling with specified interval.",
"type": "number"
}
]
},
"stdin": {
"description": "Stop watching when stdin stream has ended",
"type": "boolean"
}
}
},
"WebpackPluginFunction": {
"description": "Function acting as plugin",
"instanceof": "Function",
@ -2199,34 +2229,11 @@
},
"watchOptions": {
"description": "Options for the watcher",
"type": "object",
"additionalProperties": false,
"properties": {
"aggregateTimeout": {
"description": "Delay the rebuilt after the first change. Value is a time in ms.",
"type": "number"
},
"ignored": {
"description": "Ignore some files from watching"
},
"poll": {
"description": "Enable polling mode for watching",
"anyOf": [
{
"description": "`true`: use polling.",
"type": "boolean"
},
{
"description": "`number`: use polling with specified interval.",
"type": "number"
}
]
},
"stdin": {
"description": "Stop watching when stdin stream has ended",
"type": "boolean"
"anyOf": [
{
"$ref": "#/definitions/WatchOptions"
}
}
]
}
}
}