Skip to content

Commit

Permalink
Merge pull request #7116 from webpack/feature/main-template-type-support
Browse files Browse the repository at this point in the history
Types: Main Template is now Typed with JSDoc Annotations
  • Loading branch information
TheLarkInn committed May 3, 2018
2 parents 7829a0b + fdcafe6 commit fc3774a
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 7 deletions.
20 changes: 20 additions & 0 deletions lib/ChunkTemplate.js
Expand Up @@ -6,6 +6,21 @@

const { Tapable, SyncWaterfallHook, SyncHook } = require("tapable");

/** @typedef {import("./ModuleTemplate")} ModuleTemplate */
/** @typedef {import("./Chunk")} Chunk */
/** @typedef {import("./Module")} Module} */
/** @typedef {import("crypto").Hash} Hash */

/**
* @typedef {Object} RenderManifestOptions
* @property {Chunk} chunk the chunk used to render
* @property {Hash} hash
* @property {string} fullHash
* @property {any} outputOptions
* @property {{javascript: ModuleTemplate, webassembly: ModuleTemplate}} moduleTemplates
* @property {Map} dependencyTemplates
*/

module.exports = class ChunkTemplate extends Tapable {
constructor(outputOptions) {
super();
Expand All @@ -30,6 +45,11 @@ module.exports = class ChunkTemplate extends Tapable {
};
}

/**
*
* @param {RenderManifestOptions} options render manifest options
* @returns {any[]} returns render manifest
*/
getRenderManifest(options) {
const result = [];

Expand Down
62 changes: 62 additions & 0 deletions lib/MainTemplate.js
Expand Up @@ -18,6 +18,22 @@ const {
} = require("tapable");
const Template = require("./Template");

/** @typedef {import("webpack-sources").ConcatSource} ConcatSource */
/** @typedef {import("./ModuleTemplate")} ModuleTemplate */
/** @typedef {import("./Chunk")} Chunk */
/** @typedef {import("./Module")} Module} */
/** @typedef {import("crypto").Hash} Hash} */

/**
* @typedef {Object} RenderManifestOptions
* @property {Chunk} chunk the chunk used to render
* @property {Hash} hash
* @property {string} fullHash
* @property {any} outputOptions
* @property {{javascript: ModuleTemplate, webassembly: ModuleTemplate}} moduleTemplates
* @property {Map} dependencyTemplates
*/

// require function shortcuts:
// __webpack_require__.s = the module id of the entry point
// __webpack_require__.c = the module cache
Expand All @@ -35,10 +51,16 @@ const Template = require("./Template");
// __webpack_require__.nc = the script nonce

module.exports = class MainTemplate extends Tapable {
/**
*
* @param {any=} outputOptions output options for the MainTemplate
*/
constructor(outputOptions) {
super();
/** @type {any?} */
this.outputOptions = outputOptions || {};
this.hooks = {
/** @type {SyncWaterfallHook<any[], RenderManifestOptions>} */
renderManifest: new SyncWaterfallHook(["result", "options"]),
modules: new SyncWaterfallHook([
"modules",
Expand Down Expand Up @@ -104,6 +126,7 @@ module.exports = class MainTemplate extends Tapable {
hotBootstrap: new SyncWaterfallHook(["source", "chunk", "hash"])
};
this.hooks.startup.tap("MainTemplate", (source, chunk, hash) => {
/** @type {string[]} */
const buf = [];
if (chunk.entryModule) {
buf.push("// Load entry module and return exports");
Expand Down Expand Up @@ -296,6 +319,11 @@ module.exports = class MainTemplate extends Tapable {
this.requireFn = "__webpack_require__";
}

/**
*
* @param {RenderManifestOptions} options render manifest options
* @returns {any[]} returns render manifest
*/
getRenderManifest(options) {
const result = [];

Expand All @@ -304,6 +332,14 @@ module.exports = class MainTemplate extends Tapable {
return result;
}

/**
*
* @param {string} hash hash to be used for render call
* @param {Chunk} chunk Chunk instance
* @param {ModuleTemplate} moduleTemplate ModuleTemplate instance for render
* @param {any} dependencyTemplates DependencyTemplate[]s
* @return {ConcatSource} the newly generated source from rendering
*/
render(hash, chunk, moduleTemplate, dependencyTemplates) {
const buf = [];
buf.push(
Expand Down Expand Up @@ -349,6 +385,13 @@ module.exports = class MainTemplate extends Tapable {
return new ConcatSource(source, ";");
}

/**
*
* @param {string} hash hash for render fn
* @param {Chunk} chunk Chunk instance for require
* @param {(number|string)=} varModuleId module id
* @return {any} the moduleRequire hook call return signature
*/
renderRequireFunctionForModule(hash, chunk, varModuleId) {
return this.hooks.moduleRequire.call(
this.requireFn,
Expand All @@ -358,6 +401,14 @@ module.exports = class MainTemplate extends Tapable {
);
}

/**
*
* @param {string} hash hash for render add fn
* @param {Chunk} chunk Chunk instance for require add fn
* @param {(string|number)=} varModuleId module id
* @param {Module} varModule Module instance
* @return {any} renderAddModule call
*/
renderAddModule(hash, chunk, varModuleId, varModule) {
return this.hooks.addModule.call(
`modules[${varModuleId}] = ${varModule};`,
Expand All @@ -368,6 +419,12 @@ module.exports = class MainTemplate extends Tapable {
);
}

/**
*
* @param {string} hash string hash
* @param {number} length length
* @return {any} call hook return
*/
renderCurrentHashCode(hash, length) {
length = length || Infinity;
return this.hooks.currentHash.call(
Expand All @@ -376,6 +433,11 @@ module.exports = class MainTemplate extends Tapable {
);
}

/**
*
* @param {object} options get public path options
* @return {any} hook call
*/
getPublicPath(options) {
return this.hooks.assetPath.call(
this.outputOptions.publicPath || "",
Expand Down
4 changes: 3 additions & 1 deletion lib/Module.js
Expand Up @@ -12,7 +12,6 @@ const SortableSet = require("./util/SortableSet");
const Template = require("./Template");

/** @typedef {typeof import("./Chunk")} Chunk */

/** @typedef {typeof import("./RequestShortener")} RequestShortener */

const EMPTY_RESOLVE_OPTIONS = {};
Expand Down Expand Up @@ -101,6 +100,9 @@ class Module extends DependenciesBlock {

/** @type {boolean} */
this.useSourceMap = false;

// info from build
this._source = null;
}

get exportsArgument() {
Expand Down
97 changes: 91 additions & 6 deletions lib/Template.js
Expand Up @@ -2,9 +2,13 @@
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
/** @typedef {import("./Module")} Module */
/** @typedef {import("./Chunk")} Chunk */
/** @typedef {import("./ModuleTemplate")} ModuleTemplate */
/** @typedef {import("webpack-sources").ConcatSource} ConcatSource */

const { ConcatSource } = require("webpack-sources");
const HotUpdateChunk = require("./HotUpdateChunk");

const START_LOWERCASE_ALPHABET_CODE = "a".charCodeAt(0);
const START_UPPERCASE_ALPHABET_CODE = "A".charCodeAt(0);
Expand All @@ -18,6 +22,20 @@ const COMMENT_END_REGEX = /\*\//g;
const PATH_NAME_NORMALIZE_REPLACE_REGEX = /[^a-zA-Z0-9_!§$()=\-^°]+/g;
const MATCH_PADDED_HYPHENS_REPLACE_REGEX = /^-|-$/g;

/**
* @typedef {Object} HasId
* @property {number} id
* */

/**
* @typedef {(m: Module, idx: number) => boolean} ModuleFilterPredicate
*/

/**
* @param {HasId} a first id object to be sorted
* @param {HasId} b second id object to be sorted against
* @return {-1|0|1} the sort value
*/
const stringifyIdSortPredicate = (a, b) => {
var aId = a.id + "";
var bId = b.id + "";
Expand All @@ -26,36 +44,63 @@ const stringifyIdSortPredicate = (a, b) => {
return 0;
};

//TODO: Change type to Module when import works
//https://github.com/Microsoft/TypeScript/issues/23375
/**
* @param {HasId} module the module to compare against
* @return {boolean} return true if module.id is equal to type "number"
*/
const moduleIdIsNumber = module => {
return typeof module.id === "number";
};

module.exports = class Template {
class Template {
/**
*
* @param {Function} fn - a runtime function (.runtime.js) "template"
* @return {string} the updated and normalized function string
*/
static getFunctionContent(fn) {
return fn
.toString()
.replace(FUNCTION_CONTENT_REGEX, "")
.replace(INDENT_MULTILINE_REGEX, "")
.replace(LINE_SEPARATOR_REGEX, "\n");
}

/**
* @param {string} str the string converted to identifier
* @return {string} created identifier
*/
static toIdentifier(str) {
if (typeof str !== "string") return "";
return str
.replace(IDENTIFIER_NAME_REPLACE_REGEX, "_$1")
.replace(IDENTIFIER_ALPHA_NUMERIC_NAME_REPLACE_REGEX, "_");
}

/**
*
* @param {string} str string to be converted to commented in bundle code
* @return {string} returns a commented version of string
*/
static toComment(str) {
if (!str) return "";
return `/*! ${str.replace(COMMENT_END_REGEX, "* /")} */`;
}

/**
*
* @param {string} str string to be converted to "normal comment"
* @return {string} returns a commented version of string
*/
static toNormalComment(str) {
if (!str) return "";
return `/* ${str.replace(COMMENT_END_REGEX, "* /")} */`;
}

/**
* @param {string} str string path to be normalized
* @return {string} normalized bundle-safe path
*/
static toPath(str) {
if (typeof str !== "string") return "";
return str
Expand All @@ -64,6 +109,11 @@ module.exports = class Template {
}

// map number to a single character a-z, A-Z or <_ + number> if number is too big
/**
*
* @param {number} n number to convert to ident
* @return {string} returns single character ident
*/
static numberToIdentifer(n) {
// lower case
if (n < DELTA_A_TO_Z)
Expand All @@ -81,6 +131,11 @@ module.exports = class Template {
);
}

/**
*
* @param {string | string[]} str string to convert to identity
* @return {string} converted identity
*/
static indent(str) {
if (Array.isArray(str)) {
return str.map(Template.indent).join("\n");
Expand All @@ -92,6 +147,12 @@ module.exports = class Template {
}
}

/**
*
* @param {string|string[]} str string to create prefix for
* @param {string} prefix prefix to compose
* @return {string} returns new prefix string
*/
static prefix(str, prefix) {
if (Array.isArray(str)) {
str = str.join("\n");
Expand All @@ -102,13 +163,24 @@ module.exports = class Template {
return ind + str.replace(/\n([^\n])/g, "\n" + prefix + "$1");
}

/**
*
* @param {string|string[]} str string or string collection
* @return {string} returns a single string from array
*/
static asString(str) {
if (Array.isArray(str)) {
return str.join("\n");
}
return str;
}

/**
*
* @param {HasId[]} modules - a collection of modules to get array bounds for
* @return {[number, number] | false} returns the upper and lower array bounds
* or false if not every module has a number based id
*/
static getModulesArrayBounds(modules) {
if (!modules.every(moduleIdIsNumber)) return false;
var maxId = -Infinity;
Expand All @@ -133,6 +205,15 @@ module.exports = class Template {
return arrayOverhead < objectOverhead ? [minId, maxId] : false;
}

/**
*
* @param {Chunk} chunk chunk whose modules will be rendered
* @param {ModuleFilterPredicate} filterFn function used to filter modules from chunk to render
* @param {ModuleTemplate} moduleTemplate ModuleTemplate instance used to render modules
* @param {any | any[]} dependencyTemplates templates needed for each module to render dependencies
* @param {string=} prefix applying prefix strings
* @return {ConcatSource} rendered chunk modules in a Source object
*/
static renderChunkModules(
chunk,
filterFn,
Expand All @@ -143,7 +224,9 @@ module.exports = class Template {
if (!prefix) prefix = "";
var source = new ConcatSource();
const modules = chunk.getModules().filter(filterFn);
var removedModules = chunk.removedModules;
if (chunk instanceof HotUpdateChunk) {
var removedModules = chunk.removedModules;
}
if (
modules.length === 0 &&
(!removedModules || removedModules.length === 0)
Expand Down Expand Up @@ -202,4 +285,6 @@ module.exports = class Template {
}
return source;
}
};
}

module.exports = Template;

0 comments on commit fc3774a

Please sign in to comment.