Skip to content

Commit

Permalink
Merge pull request #9391 from vankop/create-hash-typescript
Browse files Browse the repository at this point in the history
esdoc(createHash)
  • Loading branch information
sokra committed Jul 15, 2019
2 parents e4a1241 + bf1a24a commit 0beeb7e
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 23 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.js
Expand Up @@ -71,7 +71,8 @@ module.exports = {
};
return acc;
}, {})),
extends: "extends"
extends: "extends",
constructor: "constructor"
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion declarations/WebpackOptions.d.ts
Expand Up @@ -1094,7 +1094,7 @@ export interface OutputOptions {
/**
* Algorithm used for generation the hash (see node.js crypto package)
*/
hashFunction?: string | (new () => import("../lib/util/createHash").Hash);
hashFunction?: string | import("../lib/util/createHash").HashConstructor;
/**
* Any string which is added to the hash to salt it
*/
Expand Down
43 changes: 43 additions & 0 deletions lib/AbstractMethodError.js
@@ -0,0 +1,43 @@
"use strict";

const WebpackError = require("./WebpackError");
const CURRENT_METHOD_REGEXP = /at ([a-zA-Z0-9_.]*)/;

/**
* @param {string=} method method name
* @returns {string} message
*/
function createMessage(method) {
return `Abstract method${method ? " " + method : ""}. Must be overridden.`;
}

/**
* @constructor
*/
function Message() {
this.stack = undefined;
Error.captureStackTrace(this);
/** @type {RegExpMatchArray} */
const match = this.stack.split("\n")[3].match(CURRENT_METHOD_REGEXP);

this.message = match && match[1] ? createMessage(match[1]) : createMessage();
}

/**
* Error for abstract method
* @example
* class FooClass {
* abstractMethod() {
* throw new AbstractMethodError(); // error message: Abstract method FooClass.abstractMethod. Must be overriden.
* }
* }
*
*/
class AbstractMethodError extends WebpackError {
constructor() {
super(new Message().message);
this.name = "AbstractMethodError";
}
}

module.exports = AbstractMethodError;
8 changes: 4 additions & 4 deletions lib/Compilation.js
Expand Up @@ -2294,7 +2294,7 @@ class Compilation extends Tapable {
const module = modules[i];
const moduleHash = createHash(hashFunction);
module.updateHash(moduleHash);
module.hash = moduleHash.digest(hashDigest);
module.hash = /** @type {string} */ (moduleHash.digest(hashDigest));
module.renderedHash = module.hash.substr(0, hashDigestLength);
}
// clone needed as sort below is inplace mutation
Expand Down Expand Up @@ -2329,15 +2329,15 @@ class Compilation extends Tapable {
this.dependencyTemplates
);
this.hooks.chunkHash.call(chunk, chunkHash);
chunk.hash = chunkHash.digest(hashDigest);
chunk.hash = /** @type {string} */ (chunkHash.digest(hashDigest));
hash.update(chunk.hash);
chunk.renderedHash = chunk.hash.substr(0, hashDigestLength);
this.hooks.contentHash.call(chunk);
} catch (err) {
this.errors.push(new ChunkRenderError(chunk, "", err));
}
}
this.fullHash = hash.digest(hashDigest);
this.fullHash = /** @type {string} */ (hash.digest(hashDigest));
this.hash = this.fullHash.substr(0, hashDigestLength);
}

Expand All @@ -2353,7 +2353,7 @@ class Compilation extends Tapable {
const hash = createHash(hashFunction);
hash.update(this.fullHash);
hash.update(update);
this.fullHash = hash.digest(hashDigest);
this.fullHash = /** @type {string} */ (hash.digest(hashDigest));
this.hash = this.fullHash.substr(0, hashDigestLength);
}

Expand Down
4 changes: 3 additions & 1 deletion lib/HashedModuleIdsPlugin.js
Expand Up @@ -45,7 +45,9 @@ class HashedModuleIdsPlugin {
});
const hash = createHash(options.hashFunction);
hash.update(id);
const hashId = hash.digest(options.hashDigest);
const hashId = /** @type {string} */ (hash.digest(
options.hashDigest
));
let len = options.hashDigestLength;
while (usedIds.has(hashId.substr(0, len))) len++;
module.id = hashId.substr(0, len);
Expand Down
5 changes: 2 additions & 3 deletions lib/JavascriptModulesPlugin.js
Expand Up @@ -148,9 +148,8 @@ class JavascriptModulesPlugin {
hash.update(m.hash);
}
}
chunk.contentHash.javascript = hash
.digest(hashDigest)
.substr(0, hashDigestLength);
const digest = /** @type {string} */ (hash.digest(hashDigest));
chunk.contentHash.javascript = digest.substr(0, hashDigestLength);
});
}
);
Expand Down
3 changes: 2 additions & 1 deletion lib/ModuleFilenameHelpers.js
Expand Up @@ -44,7 +44,8 @@ const getBefore = (str, token) => {
const getHash = str => {
const hash = createHash("md4");
hash.update(str);
return hash.digest("hex").substr(0, 4);
const digest = /** @type {string} */ (hash.digest("hex"));
return digest.substr(0, 4);
};

const asRegExp = test => {
Expand Down
3 changes: 2 additions & 1 deletion lib/NamedModulesPlugin.js
Expand Up @@ -10,7 +10,8 @@ const RequestShortener = require("./RequestShortener");
const getHash = str => {
const hash = createHash("md4");
hash.update(str);
return hash.digest("hex").substr(0, 4);
const digest = /** @type {string} */ (hash.digest("hex"));
return digest.substr(0, 4);
};

class NamedModulesPlugin {
Expand Down
2 changes: 1 addition & 1 deletion lib/NormalModule.js
Expand Up @@ -405,7 +405,7 @@ class NormalModule extends Module {
}
hash.update("meta");
hash.update(JSON.stringify(this.buildMeta));
this._buildHash = hash.digest("hex");
this._buildHash = /** @type {string} */ (hash.digest("hex"));
}

build(options, compilation, resolver, fs, callback) {
Expand Down
66 changes: 57 additions & 9 deletions lib/util/createHash.js
Expand Up @@ -4,21 +4,50 @@
*/
"use strict";

/** @typedef {{new(): Hash}} HashConstructor */
/**
* @typedef {Object} Hash
* @property {function(string|Buffer, string=): Hash} update
* @property {function(string): string} digest
*/
const AbstractMethodError = require("../AbstractMethodError");

const BULK_SIZE = 1000;

class BulkUpdateDecorator {
class Hash {
/**
* Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding}
* @param {string|Buffer} data data
* @param {string=} inputEncoding data encoding
* @returns {this} updated hash
*/
update(data, inputEncoding) {
throw new AbstractMethodError();
}

/**
* Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding}
* @param {string=} encoding encoding of the return value
* @returns {string|Buffer} digest
*/
digest(encoding) {
throw new AbstractMethodError();
}
}

exports.Hash = Hash;
/** @typedef {typeof Hash} HashConstructor */

class BulkUpdateDecorator extends Hash {
/**
* @param {Hash} hash hash
*/
constructor(hash) {
super();
this.hash = hash;
this.buffer = "";
}

/**
* Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding}
* @param {string|Buffer} data data
* @param {string=} inputEncoding data encoding
* @returns {this} updated hash
*/
update(data, inputEncoding) {
if (
inputEncoding !== undefined ||
Expand All @@ -40,6 +69,11 @@ class BulkUpdateDecorator {
return this;
}

/**
* Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding}
* @param {string=} encoding encoding of the return value
* @returns {string|Buffer} digest
*/
digest(encoding) {
if (this.buffer.length > 0) {
this.hash.update(this.buffer);
Expand All @@ -51,18 +85,32 @@ class BulkUpdateDecorator {
}
}

/* istanbul ignore next */
class DebugHash {
/**
* istanbul ignore next
*/
class DebugHash extends Hash {
constructor() {
super();
this.string = "";
}

/**
* Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding}
* @param {string|Buffer} data data
* @param {string=} inputEncoding data encoding
* @returns {this} updated hash
*/
update(data, inputEncoding) {
if (typeof data !== "string") data = data.toString("utf-8");
this.string += data;
return this;
}

/**
* Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding}
* @param {string=} encoding encoding of the return value
* @returns {string|Buffer} digest
*/
digest(encoding) {
return this.string.replace(/[^a-z0-9]+/gi, m =>
Buffer.from(m).toString("hex")
Expand Down
2 changes: 1 addition & 1 deletion schemas/WebpackOptions.json
Expand Up @@ -905,7 +905,7 @@
},
{
"instanceof": "Function",
"tsType": "(new () => import('../lib/util/createHash').Hash)"
"tsType": "import('../lib/util/createHash').HashConstructor"
}
]
},
Expand Down
27 changes: 27 additions & 0 deletions test/AbstractMethodError.unittest.js
@@ -0,0 +1,27 @@
"use strict";

const AbstractMethodError = require("../lib/AbstractMethodError");

describe("WebpackError", () => {
class Foo {
abstractMethod() {
return new AbstractMethodError();
}
}

class Child extends Foo {}

const expectedMessage = "Abstract method $1. Must be overridden.";

it("Should construct message with caller info", () => {
const fooClassError = new Foo().abstractMethod();
const childClassError = new Child().abstractMethod();

expect(fooClassError.message).toBe(
expectedMessage.replace("$1", "Foo.abstractMethod")
);
expect(childClassError.message).toBe(
expectedMessage.replace("$1", "Child.abstractMethod")
);
});
});

0 comments on commit 0beeb7e

Please sign in to comment.