diff --git a/packages/assetpack/src/core/utils/getHash.ts b/packages/assetpack/src/core/utils/getHash.ts index 292ca32..032d6a0 100644 --- a/packages/assetpack/src/core/utils/getHash.ts +++ b/packages/assetpack/src/core/utils/getHash.ts @@ -11,7 +11,8 @@ export function getHash(input: string | Buffer): string { input = fs.readFileSync(input); } - const checksumHex = crc32.crc32(input).toString(16); + // Pad to 8 hex digits: Buffer.from drops the last digit of an odd-length hex string. + const checksumHex = crc32.crc32(input).toString(16).padStart(8, '0'); return Buffer.from(checksumHex, 'hex').toString('base64url'); } diff --git a/packages/assetpack/test/core/Utils.test.ts b/packages/assetpack/test/core/Utils.test.ts index 2e589e4..eea8a4c 100644 --- a/packages/assetpack/test/core/Utils.test.ts +++ b/packages/assetpack/test/core/Utils.test.ts @@ -2,7 +2,9 @@ import { describe, expect, it } from 'vitest'; import { AssetPack } from '../../src/core/AssetPack.js'; import { extractTagsFromFileName } from '../../src/core/utils/extractTagsFromFileName.js'; import { generateCacheName } from '../../src/core/utils/generateCacheName.js'; +import { getHash } from '../../src/core/utils/getHash.js'; import { createAssetPipe, createFolder, getCacheDir, getInputDir, getOutputDir } from '../utils/index.js'; +import crc32 from '@node-rs/crc32'; import type { Asset } from '../../src/core/Asset.js'; import type { AssetPipe } from '../../src/core/index.js'; @@ -208,4 +210,24 @@ describe('Utils', () => { expect(cacheName3).toEqual('ab900fa81d7121ea46bd2eafe9e826633c1c48a0'); }); + + it('should always return a 6 character hash', () => { + const findInput = (accept: (crc: number) => boolean) => { + for (let i = 0; ; i++) { + const buffer = Buffer.from(`asset-${i}`); + + if (accept(crc32.crc32(buffer))) return buffer; + } + }; + + // crc32 values with 1, 2 and 3 leading zero hex digits + for (const limit of [0x10000000, 0x1000000, 0x100000]) { + expect(getHash(findInput((crc) => crc < limit))).toMatch(/^[\w-]{6}$/); + } + + // hashes without a leading zero are unchanged + const buffer = findInput((crc) => crc >= 0x10000000); + + expect(getHash(buffer)).toBe(Buffer.from(crc32.crc32(buffer).toString(16), 'hex').toString('base64url')); + }); }); diff --git a/packages/assetpack/test/manifest/Manifest.test.ts b/packages/assetpack/test/manifest/Manifest.test.ts index 0bfb057..603229a 100644 --- a/packages/assetpack/test/manifest/Manifest.test.ts +++ b/packages/assetpack/test/manifest/Manifest.test.ts @@ -630,10 +630,10 @@ describe('Manifest', () => { src: [ { src: 'bundle/sprite-vUcaag@0.5x.astc.ktx', progressSize: 4.98 }, { src: 'bundle/sprite-TZpmeQ.astc.ktx', progressSize: 16.57 }, - { src: 'bundle/sprite-sDtC@0.5x.png', progressSize: 5.21 }, { src: 'bundle/sprite-KdyNpA@0.5x.webp', progressSize: 3.78 }, { src: 'bundle/sprite-k07jiw.png', progressSize: 14.49 }, - { src: 'bundle/sprite-3CLG.webp', progressSize: 8.2 }, + { src: 'bundle/sprite-CwO0Lg@0.5x.png', progressSize: 5.21 }, + { src: 'bundle/sprite-ANwixg.webp', progressSize: 8.2 }, ], data: { tags: { @@ -645,7 +645,7 @@ describe('Manifest', () => { alias: ['bundle/tps'], src: [ { src: 'bundle/tps-RzSARA-0@0.5x.astc.json', progressSize: 26.52 }, - { src: 'bundle/tps-Ktro9A-0@0.5x.png.json', progressSize: 21.3 }, + { src: 'bundle/tps-qrwSUA-0@0.5x.png.json', progressSize: 21.3 }, { src: 'bundle/tps-iS-Jog-0@0.5x.webp.json', progressSize: 19.45 }, { src: 'bundle/tps-G92JcQ-0.png.json', progressSize: 71.01 }, { src: 'bundle/tps-g4NIDQ-0.astc.json', progressSize: 90.82 }, @@ -697,8 +697,8 @@ describe('Manifest', () => { { alias: ['spine/dragon.atlas'], src: [ - { src: 'spine/dragon-VMxv5A@0.5x.atlas', progressSize: 0.86 }, { src: 'spine/dragon-bOhE1A.atlas', progressSize: 0.89 }, + { src: 'spine/dragon-_efU3A@0.5x.atlas', progressSize: 0.86 }, ], data: { tags: { @@ -1951,7 +1951,7 @@ describe('Manifest', () => { { src: 'bundle/sprite-vUcaag@0.5x.astc.ktx', progressSize: 4.98 }, { src: 'bundle/sprite-TZpmeQ.astc.ktx', progressSize: 16.57 }, { src: 'bundle/sprite-KdyNpA@0.5x.webp', progressSize: 3.78 }, - { src: 'bundle/sprite-3CLG.webp', progressSize: 8.2 }, + { src: 'bundle/sprite-ANwixg.webp', progressSize: 8.2 }, ], data: { tags: { m: true } }, }, @@ -2017,10 +2017,10 @@ describe('Manifest', () => { { alias: ['spine/dragon.atlas'], src: [ + { src: 'spine/dragon-nYsr1g@0.5x.webp.atlas', progressSize: 0.87 }, { src: 'spine/dragon-JospZg@0.5x.astc.atlas', progressSize: 0.87 }, { src: 'spine/dragon-gYS0Qg.webp.atlas', progressSize: 0.89 }, { src: 'spine/dragon-9M9x8w.astc.atlas', progressSize: 0.89 }, - { src: 'spine/dragon-672U@0.5x.webp.atlas', progressSize: 0.86 }, ], data: { tags: { spine: true }, spine: true }, },