From 1ab66d5d6563451a7933cff08b3d6dd7747f1524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=F0=9F=8E=83=20Khripkov?= Date: Thu, 30 May 2024 20:53:15 +0300 Subject: [PATCH 1/7] feat: add base64-save digestType; --- README.md | 8 +++++--- lib/getHashDigest.js | 12 +++++++++++- lib/interpolateName.js | 2 +- test/getHashDigest.test.js | 8 ++++++++ 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a9aee06..c2bada1 100644 --- a/README.md +++ b/README.md @@ -76,17 +76,19 @@ The following tokens are replaced in the `name` parameter: - `[contenthash]` the hash of `options.content` (Buffer) (by default it's the hex digest of the `xxhash64` hash) - `[:contenthash::]` optionally one can configure - other `hashType`s, i. e. `xxhash64`, `sha1`, `md4` (wasm version), `native-md4` (`crypto` module version), `md5`, `sha256`, `sha512` - - other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64` + - other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`, `base64-safe` - and `length` the length in chars - `[hash]` the hash of `options.content` (Buffer) (by default it's the hex digest of the `xxhash64` hash) - `[:hash::]` optionally one can configure - other `hashType`s, i. e. `xxhash64`, `sha1`, `md4` (wasm version), `native-md4` (`crypto` module version), `md5`, `sha256`, `sha512` - - other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64` + - other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`, `base64-safe` - and `length` the length in chars - `[N]` the N-th match obtained from matching the current file name against `options.regExp` In loader context `[hash]` and `[contenthash]` are the same, but we recommend using `[contenthash]` for avoid misleading. +`digestType` with `base64-safe` don't contain `/`, `+` and `=` symbols. + Examples ```javascript @@ -157,7 +159,7 @@ const digestString = loaderUtils.getHashDigest( - `buffer` the content that should be hashed - `hashType` one of `xxhash64`, `sha1`, `md4`, `md5`, `sha256`, `sha512` or any other node.js supported hash type -- `digestType` one of `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64` +- `digestType` one of `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`, `base64-safe` - `maxLength` the maximum length in chars ## License diff --git a/lib/getHashDigest.js b/lib/getHashDigest.js index 600b86e..0a58949 100644 --- a/lib/getHashDigest.js +++ b/lib/getHashDigest.js @@ -64,6 +64,12 @@ function getHashDigest(buffer, algorithm, digestType, maxLength) { algorithm = algorithm || "xxhash64"; maxLength = maxLength || 9999; + const makeSafe = digestType && digestType.endsWith('-safe'); + if (makeSafe) { + // remove '-safe' from 'digestType' + digestType = digestType.slice(0, -5) + } + let hash; if (algorithm === "xxhash64") { @@ -124,7 +130,11 @@ function getHashDigest(buffer, algorithm, digestType, maxLength) { ) { return encodeBufferToBase(hash.digest(), digestType.substr(4), maxLength); } else { - return hash.digest(digestType || "hex").substr(0, maxLength); + let hashResult = hash.digest(digestType || 'hex').substr(0, maxLength); + if (makeSafe) { + return hashResult.replaceAll('/', '_').replaceAll('+', '-').replaceAll('=', '') + } + return hashResult } } diff --git a/lib/interpolateName.js b/lib/interpolateName.js index 60a898c..54d1ea5 100644 --- a/lib/interpolateName.js +++ b/lib/interpolateName.js @@ -77,7 +77,7 @@ function interpolateName(loaderContext, name, options = {}) { // `hash` and `contenthash` are same in `loader-utils` context // let's keep `hash` for backward compatibility .replace( - /\[(?:([^[:\]]+):)?(?:hash|contenthash)(?::([a-z]+\d*))?(?::(\d+))?\]/gi, + /\[(?:([^[:\]]+):)?(?:hash|contenthash)(?::([a-z]+\d*(?:-safe)?))?(?::(\d+))?\]/gi, (all, hashType, digestType, maxLength) => getHashDigest(content, hashType, digestType, parseInt(maxLength, 10)) ); diff --git a/test/getHashDigest.test.js b/test/getHashDigest.test.js index e993f11..e0dc238 100644 --- a/test/getHashDigest.test.js +++ b/test/getHashDigest.test.js @@ -21,6 +21,7 @@ describe("getHashDigest()", () => { ["abc\\0💩", "md4", "hex", undefined, "45aa5b332f8e562aaf0106ad6fc1d78f"], ["abc\\0💩", "md4", "base64", undefined, "RapbMy+OViqvAQatb8HXjw=="], ["abc\\0♥", "md4", "base64", undefined, "Rrlif+z0m4Dq8BwB2Grp/Q=="], + ["abc\\0♥", "md4", "base64-safe", undefined, "Rrlif-z0m4Dq8BwB2Grp_Q"], ["abc\\0💩", "md4", "base52", undefined, "dtXZENFEkYHXGxOkJbevPoD"], ["abc\\0♥", "md4", "base52", undefined, "fYFFcfXRGsVweukHKlPayHs"], @@ -78,6 +79,13 @@ describe("getHashDigest()", () => { expect(hashDigest).toBe(test[4]); } ); + + // it('for', () => { + // for(let i = 0; i < 100; i += 1) { + // const result = loaderUtils.getHashDigest(`a-${i}`, "xxhash64", "base64") + // expect(result).toMatch(/^[a-zA-Z_][a-zA-Z\d-_]*$/g); + // } + // }) }); }); From 8055354a78087722486bf1a84273113a1c8dd107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=F0=9F=8E=83=20Khripkov?= Date: Thu, 30 May 2024 20:56:46 +0300 Subject: [PATCH 2/7] fix: lints; --- lib/getHashDigest.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/getHashDigest.js b/lib/getHashDigest.js index 0a58949..4a7aaea 100644 --- a/lib/getHashDigest.js +++ b/lib/getHashDigest.js @@ -64,10 +64,10 @@ function getHashDigest(buffer, algorithm, digestType, maxLength) { algorithm = algorithm || "xxhash64"; maxLength = maxLength || 9999; - const makeSafe = digestType && digestType.endsWith('-safe'); + const makeSafe = digestType && digestType.endsWith("-safe"); if (makeSafe) { // remove '-safe' from 'digestType' - digestType = digestType.slice(0, -5) + digestType = digestType.slice(0, -5); } let hash; @@ -130,11 +130,14 @@ function getHashDigest(buffer, algorithm, digestType, maxLength) { ) { return encodeBufferToBase(hash.digest(), digestType.substr(4), maxLength); } else { - let hashResult = hash.digest(digestType || 'hex').substr(0, maxLength); + const hashResult = hash.digest(digestType || "hex").substr(0, maxLength); if (makeSafe) { - return hashResult.replaceAll('/', '_').replaceAll('+', '-').replaceAll('=', '') + return hashResult + .replaceAll("/", "_") + .replaceAll("+", "-") + .replaceAll("=", ""); } - return hashResult + return hashResult; } } From 5dd852779b4e085d9987415cd950ea08c6a03c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=F0=9F=8E=83=20Khripkov?= Date: Thu, 30 May 2024 20:59:45 +0300 Subject: [PATCH 3/7] fix: rm dev code; --- test/getHashDigest.test.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/getHashDigest.test.js b/test/getHashDigest.test.js index e0dc238..929c474 100644 --- a/test/getHashDigest.test.js +++ b/test/getHashDigest.test.js @@ -79,13 +79,6 @@ describe("getHashDigest()", () => { expect(hashDigest).toBe(test[4]); } ); - - // it('for', () => { - // for(let i = 0; i < 100; i += 1) { - // const result = loaderUtils.getHashDigest(`a-${i}`, "xxhash64", "base64") - // expect(result).toMatch(/^[a-zA-Z_][a-zA-Z\d-_]*$/g); - // } - // }) }); }); From fa8de8ff7c755aee13256c969e1e859185c4ac36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20=F0=9F=8E=83=20Khripkov?= Date: Thu, 30 May 2024 21:13:00 +0300 Subject: [PATCH 4/7] fix: change replaceAll to replace with regex; --- lib/getHashDigest.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/getHashDigest.js b/lib/getHashDigest.js index 4a7aaea..21b28d0 100644 --- a/lib/getHashDigest.js +++ b/lib/getHashDigest.js @@ -133,9 +133,9 @@ function getHashDigest(buffer, algorithm, digestType, maxLength) { const hashResult = hash.digest(digestType || "hex").substr(0, maxLength); if (makeSafe) { return hashResult - .replaceAll("/", "_") - .replaceAll("+", "-") - .replaceAll("=", ""); + .replace(/\//g, "_") + .replace(/\+/g, "-") + .replace(/=/g, ""); } return hashResult; } From bb961ec1ed60ee2a78815571160bf6ad1d66dabb Mon Sep 17 00:00:00 2001 From: "alexander.akait" Date: Tue, 4 Jun 2024 20:36:55 +0300 Subject: [PATCH 5/7] refactor: improve --- README.md | 6 +++--- lib/getHashDigest.js | 20 ++++---------------- lib/interpolateName.js | 2 +- test/getHashDigest.test.js | 2 +- 4 files changed, 9 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index c2bada1..fdfd5de 100644 --- a/README.md +++ b/README.md @@ -76,18 +76,18 @@ The following tokens are replaced in the `name` parameter: - `[contenthash]` the hash of `options.content` (Buffer) (by default it's the hex digest of the `xxhash64` hash) - `[:contenthash::]` optionally one can configure - other `hashType`s, i. e. `xxhash64`, `sha1`, `md4` (wasm version), `native-md4` (`crypto` module version), `md5`, `sha256`, `sha512` - - other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`, `base64-safe` + - other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`, `base64safe` - and `length` the length in chars - `[hash]` the hash of `options.content` (Buffer) (by default it's the hex digest of the `xxhash64` hash) - `[:hash::]` optionally one can configure - other `hashType`s, i. e. `xxhash64`, `sha1`, `md4` (wasm version), `native-md4` (`crypto` module version), `md5`, `sha256`, `sha512` - - other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`, `base64-safe` + - other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`, `base64safe` - and `length` the length in chars - `[N]` the N-th match obtained from matching the current file name against `options.regExp` In loader context `[hash]` and `[contenthash]` are the same, but we recommend using `[contenthash]` for avoid misleading. -`digestType` with `base64-safe` don't contain `/`, `+` and `=` symbols. +`digestType` with `base64safe` don't contain `/`, `+` and `=` symbols. Examples diff --git a/lib/getHashDigest.js b/lib/getHashDigest.js index 21b28d0..232cd06 100644 --- a/lib/getHashDigest.js +++ b/lib/getHashDigest.js @@ -64,12 +64,6 @@ function getHashDigest(buffer, algorithm, digestType, maxLength) { algorithm = algorithm || "xxhash64"; maxLength = maxLength || 9999; - const makeSafe = digestType && digestType.endsWith("-safe"); - if (makeSafe) { - // remove '-safe' from 'digestType' - digestType = digestType.slice(0, -5); - } - let hash; if (algorithm === "xxhash64") { @@ -126,19 +120,13 @@ function getHashDigest(buffer, algorithm, digestType, maxLength) { digestType === "base49" || digestType === "base52" || digestType === "base58" || - digestType === "base62" + digestType === "base62" || + digestType === "base64safe" ) { return encodeBufferToBase(hash.digest(), digestType.substr(4), maxLength); - } else { - const hashResult = hash.digest(digestType || "hex").substr(0, maxLength); - if (makeSafe) { - return hashResult - .replace(/\//g, "_") - .replace(/\+/g, "-") - .replace(/=/g, ""); - } - return hashResult; } + + return hash.digest(digestType || "hex").substr(0, maxLength); } module.exports = getHashDigest; diff --git a/lib/interpolateName.js b/lib/interpolateName.js index 54d1ea5..60a898c 100644 --- a/lib/interpolateName.js +++ b/lib/interpolateName.js @@ -77,7 +77,7 @@ function interpolateName(loaderContext, name, options = {}) { // `hash` and `contenthash` are same in `loader-utils` context // let's keep `hash` for backward compatibility .replace( - /\[(?:([^[:\]]+):)?(?:hash|contenthash)(?::([a-z]+\d*(?:-safe)?))?(?::(\d+))?\]/gi, + /\[(?:([^[:\]]+):)?(?:hash|contenthash)(?::([a-z]+\d*))?(?::(\d+))?\]/gi, (all, hashType, digestType, maxLength) => getHashDigest(content, hashType, digestType, parseInt(maxLength, 10)) ); diff --git a/test/getHashDigest.test.js b/test/getHashDigest.test.js index 929c474..b95bafa 100644 --- a/test/getHashDigest.test.js +++ b/test/getHashDigest.test.js @@ -21,7 +21,7 @@ describe("getHashDigest()", () => { ["abc\\0💩", "md4", "hex", undefined, "45aa5b332f8e562aaf0106ad6fc1d78f"], ["abc\\0💩", "md4", "base64", undefined, "RapbMy+OViqvAQatb8HXjw=="], ["abc\\0♥", "md4", "base64", undefined, "Rrlif+z0m4Dq8BwB2Grp/Q=="], - ["abc\\0♥", "md4", "base64-safe", undefined, "Rrlif-z0m4Dq8BwB2Grp_Q"], + ["abc\\0♥", "md4", "base64safe", undefined, "Rrlif-z0m4Dq8BwB2Grp_Q"], ["abc\\0💩", "md4", "base52", undefined, "dtXZENFEkYHXGxOkJbevPoD"], ["abc\\0♥", "md4", "base52", undefined, "fYFFcfXRGsVweukHKlPayHs"], From 39eb7875a64bc838ef6537b589e991ef8dcf3299 Mon Sep 17 00:00:00 2001 From: "alexander.akait" Date: Tue, 4 Jun 2024 20:37:26 +0300 Subject: [PATCH 6/7] docs: fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fdfd5de..f142c6e 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,7 @@ const digestString = loaderUtils.getHashDigest( - `buffer` the content that should be hashed - `hashType` one of `xxhash64`, `sha1`, `md4`, `md5`, `sha256`, `sha512` or any other node.js supported hash type -- `digestType` one of `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`, `base64-safe` +- `digestType` one of `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`, `base64safe` - `maxLength` the maximum length in chars ## License From efd953fca8a3697e076855d6c0bc8aa471f3752a Mon Sep 17 00:00:00 2001 From: "alexander.akait" Date: Tue, 4 Jun 2024 20:41:51 +0300 Subject: [PATCH 7/7] fix: logic --- lib/getHashDigest.js | 6 +++++- test/getHashDigest.test.js | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/getHashDigest.js b/lib/getHashDigest.js index 232cd06..5cbeb6a 100644 --- a/lib/getHashDigest.js +++ b/lib/getHashDigest.js @@ -123,7 +123,11 @@ function getHashDigest(buffer, algorithm, digestType, maxLength) { digestType === "base62" || digestType === "base64safe" ) { - return encodeBufferToBase(hash.digest(), digestType.substr(4), maxLength); + return encodeBufferToBase( + hash.digest(), + digestType === "base64safe" ? 64 : digestType.substr(4), + maxLength + ); } return hash.digest(digestType || "hex").substr(0, maxLength); diff --git a/test/getHashDigest.test.js b/test/getHashDigest.test.js index b95bafa..d647a1c 100644 --- a/test/getHashDigest.test.js +++ b/test/getHashDigest.test.js @@ -21,7 +21,7 @@ describe("getHashDigest()", () => { ["abc\\0💩", "md4", "hex", undefined, "45aa5b332f8e562aaf0106ad6fc1d78f"], ["abc\\0💩", "md4", "base64", undefined, "RapbMy+OViqvAQatb8HXjw=="], ["abc\\0♥", "md4", "base64", undefined, "Rrlif+z0m4Dq8BwB2Grp/Q=="], - ["abc\\0♥", "md4", "base64safe", undefined, "Rrlif-z0m4Dq8BwB2Grp_Q"], + ["abc\\0♥", "md4", "base64safe", undefined, "3ZWmHo0hPMWE2rZeN_oHB6"], ["abc\\0💩", "md4", "base52", undefined, "dtXZENFEkYHXGxOkJbevPoD"], ["abc\\0♥", "md4", "base52", undefined, "fYFFcfXRGsVweukHKlPayHs"],