@alwatr/hash-string 5.1.0 → 5.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,24 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## <small>5.2.1 (2025-04-15)</small>
7
+
8
+ **Note:** Version bump only for package @alwatr/hash-string
9
+
10
+ ## [5.2.0](https://github.com/Alwatr/nanolib/compare/@alwatr/hash-string@5.1.0...@alwatr/hash-string@5.2.0) (2025-04-01)
11
+
12
+ ### Features
13
+
14
+ * implement DJB2 hash algorithm for efficient string hashing ([d505181](https://github.com/Alwatr/nanolib/commit/d505181fed1f85cf067ea5499b3de692b84385b0)) by @alimd
15
+
16
+ ### Bug Fixes
17
+
18
+ * change default repeat value in hashString function from 3 to 1 ([e5c373f](https://github.com/Alwatr/nanolib/commit/e5c373f2a18ce1933f234a6f8dafeda181df1f14)) by @alimd
19
+
20
+ ### Code Refactoring
21
+
22
+ * replace hashString function with nanoHash and export new hashing methods ([3651b0c](https://github.com/Alwatr/nanolib/commit/3651b0cf254a044f7eb4cfc0a52a9b645e1c26d3)) by @alimd
23
+
6
24
  ## 5.1.0 (2025-03-18)
7
25
 
8
26
  ### Features
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # hash-string
2
2
 
3
- A lightweight, high-performance utility for generating simple non-cryptographic hash strings from input values.
3
+ A lightweight, high-performance utility for generating simple hash strings from input values.
4
+ It is **non-cryptographic** but very fast and efficient. While it cannot be reversed easily and brute force attacks can take up to years for fast computers.
4
5
 
5
6
  ## Installation
6
7
 
@@ -13,22 +14,22 @@ npm install @alwatr/hash-string
13
14
  ## Usage
14
15
 
15
16
  ```typescript
16
- import {hashString} from '@alwatr/hash-string';
17
+ import {nanoHash} from '@alwatr/hash-string';
17
18
 
18
19
  // Hash a string with a prefix
19
- hashString('test', 'prefix-'); // => 'prefix-j26j3d4'
20
+ nanoHash('test', 'prefix-'); // => 'prefix-j26j3d4'
20
21
 
21
22
  // Hash a number
22
- hashString(12345, 'num-'); // => 'num-8hu3f2l'
23
+ nanoHash(12345, 'num-'); // => 'num-8hu3f2l'
23
24
 
24
25
  // Adjust complexity with repeat parameter
25
- hashString('test', 'p-', 1); // => 'p-7ba2n3y' (faster, less complex)
26
- hashString('test', 'p-', 5); // => 'p-3f72h9b' (slower, more complex)
26
+ nanoHash('test', 'p-', 1); // => 'p-7ba2n3y' (faster, less complex)
27
+ nanoHash('test', 'p-', 5); // => 'p-3f72h9b' (slower, more complex)
27
28
  ```
28
29
 
29
30
  ## API
30
31
 
31
- ### hashString(str: string | number, prefix: string, repeat = 3): string
32
+ ### nanoHash(str: string | number, prefix: string, repeat = 3): string
32
33
 
33
34
  Generates a simple hash from the input string or number.
34
35
 
@@ -38,6 +39,14 @@ Generates a simple hash from the input string or number.
38
39
 
39
40
  Returns a hashed string with the specified prefix.
40
41
 
42
+ ### djb2Hash(str: string): number
43
+
44
+ Implements the DJB2 hash algorithm, a fast and efficient string hashing function created by Daniel J. Bernstein.
45
+
46
+ - **str**: The string to hash
47
+
48
+ Returns a 32-bit unsigned integer hash value.
49
+
41
50
  ## Features
42
51
 
43
52
  - Fast and lightweight hashing algorithm
@@ -49,7 +58,9 @@ Returns a hashed string with the specified prefix.
49
58
 
50
59
  ## Security Note
51
60
 
52
- This function is designed for simple hashing needs like generating IDs or checksums. It is **not suitable** for cryptographic purposes or security-sensitive applications. While the output cannot be easily reversed, it's not designed to resist targeted attacks.
61
+ This function is designed for simple hashing needs like generating IDs or checksums. It is **non-cryptographic** but very fast and efficient. While it cannot be reversed easily and brute force attacks can take up to years for fast computers, it is still **not suitable** for security-sensitive applications or storing sensitive data. The algorithm prioritizes speed and simplicity over cryptographic strength, making it ideal for general-purpose hashing where security is not a primary concern.
62
+
63
+ For security-critical applications, use established cryptographic hash functions (like SHA-256 or Argon2) instead.
53
64
 
54
65
  ## Examples
55
66
 
@@ -57,26 +68,26 @@ This function is designed for simple hashing needs like generating IDs or checks
57
68
 
58
69
  ```typescript
59
70
  // Generate a hash for a string
60
- hashString('hello world', 'msg-'); // => 'msg-k7f2h9d'
71
+ nanoHash('hello world', 'msg-'); // => 'msg-k7f2h9d'
61
72
 
62
73
  // Generate a hash for a number
63
- hashString(42, 'id-'); // => 'id-p83b2e4'
74
+ nanoHash(42, 'id-'); // => 'id-p83b2e4'
64
75
 
65
76
  // Same input produces the same output
66
- hashString('test', 'x-') === hashString('test', 'x-'); // => true
77
+ nanoHash('test', 'x-') === nanoHash('test', 'x-'); // => true
67
78
 
68
79
  // Different inputs produce different outputs
69
- hashString('test1', 'x-') !== hashString('test2', 'x-'); // => true
80
+ nanoHash('test1', 'x-') !== nanoHash('test2', 'x-'); // => true
70
81
  ```
71
82
 
72
83
  ### Controlling Complexity
73
84
 
74
85
  ```typescript
75
86
  // Less complex (faster)
76
- hashString('password', 'user-', 1);
87
+ nanoHash('password', 'user-', 1);
77
88
 
78
89
  // More complex (slightly slower)
79
- hashString('password', 'user-', 5);
90
+ nanoHash('password', 'user-', 5);
80
91
  ```
81
92
 
82
93
  ### Use Cases
@@ -88,7 +99,7 @@ hashString('password', 'user-', 5);
88
99
 
89
100
  ## Implementation Details
90
101
 
91
- The hashing algorithm combines two 32-bit hash functions with prime number multipliers to create a distribution with good avalanche properties. This means small changes in the input produce significantly different outputs, reducing collision probability.
102
+ The hashing algorithm combines two 32-bit hash functions with prime number multipliers to create a distribution with good avalanche properties. This means small changes in the input produce significantly different outputs, reducing collision probability. Though non-cryptographic, the algorithm's computational complexity makes it resistant to casual reversal attempts.
92
103
 
93
104
  The implementation:
94
105
 
@@ -98,6 +109,25 @@ The implementation:
98
109
  4. Optionally repeats the process for increased complexity
99
110
  5. Converts the result to base-36 for compact representation
100
111
 
112
+ ### DJB2 Hash Algorithm
113
+
114
+ The package includes the DJB2 hash algorithm, a fast and efficient string hashing function created by Daniel J. Bernstein:
115
+
116
+ ```typescript
117
+ // Generate a numeric hash value
118
+ import {djb2Hash} from '@alwatr/hash-string';
119
+
120
+ const hashValue = djb2Hash("hello world"); // Returns a 32-bit unsigned integer
121
+ ```
122
+
123
+ Key features of djb2Hash:
124
+
125
+ - Fast computation with minimal operations
126
+ - Produces consistent 32-bit unsigned integer values
127
+ - Good distribution for short to medium-length strings
128
+ - Simple implementation with right-to-left iteration for performance
129
+ - Uses prime number (5381) as the initial seed
130
+
101
131
  ## Sponsors
102
132
 
103
133
  The following companies, organizations, and individuals support Nanolib ongoing maintenance and development. Become a Sponsor to get your logo on our README and website.
@@ -0,0 +1,21 @@
1
+ /**
2
+ * DJB2 Hash Algorithm - A fast string hashing function.
3
+ *
4
+ * This implementation is based on Daniel J. Bernstein's popular 'times 33' hash algorithm,
5
+ * commonly known as DJB2. It's known for its simplicity, speed, and good distribution properties
6
+ * for short strings, making it suitable for general purpose hashing needs.
7
+ *
8
+ * Performance notes:
9
+ * - Uses right-to-left iteration to avoid repeated length lookups
10
+ * - Employs bit shifting operations for faster computation
11
+ * - Final right shift ensures unsigned 32-bit integer output
12
+ *
13
+ * @param {string} str - The input string to be hashed
14
+ * @returns {number} A 32-bit unsigned integer hash value
15
+ *
16
+ * @example
17
+ * // Returns a numeric hash value
18
+ * const hashValue = djb2Hash("hello world");
19
+ */
20
+ export declare function djb2Hash(str: string): number;
21
+ //# sourceMappingURL=djb2-hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"djb2-hash.d.ts","sourceRoot":"","sources":["../src/djb2-hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAY5C"}
package/dist/main.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /* @alwatr/hash-string v5.1.0 */
1
+ /* @alwatr/hash-string v5.2.1 */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -21,12 +21,23 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  // src/main.ts
22
22
  var main_exports = {};
23
23
  __export(main_exports, {
24
- hashString: () => hashString
24
+ djb2Hash: () => djb2Hash,
25
+ nanoHash: () => nanoHash
25
26
  });
26
27
  module.exports = __toCommonJS(main_exports);
27
28
  var import_package_tracer = require("@alwatr/package-tracer");
28
- __dev_mode__: import_package_tracer.packageTracer.add("@alwatr/hash-string", "5.1.0");
29
- function hashString(str, prefix, repeat = 3) {
29
+
30
+ // src/djb2-hash.ts
31
+ function djb2Hash(str) {
32
+ let hashValue = 5381;
33
+ for (let i = str.length - 1; i >= 0; i--) {
34
+ hashValue = (hashValue << 5) + hashValue ^ str.charCodeAt(i);
35
+ }
36
+ return hashValue >>> 0;
37
+ }
38
+
39
+ // src/nano-hash.ts
40
+ function nanoHash(str, prefix, repeat = 1) {
30
41
  if (repeat < 1) {
31
42
  throw new Error("The repeat parameter must be greater than or equal to 1");
32
43
  }
@@ -35,7 +46,8 @@ function hashString(str, prefix, repeat = 3) {
35
46
  if (typeof str === "number") {
36
47
  str = str.toString();
37
48
  }
38
- for (let i = 0; i < str.length; i++) {
49
+ const len = str.length;
50
+ for (let i = 0; i < len; i++) {
39
51
  const char = str.charCodeAt(i);
40
52
  hash1 = Math.imul(hash1 ^ char, 2654435761);
41
53
  hash2 = Math.imul(hash2 ^ char, 1597334677);
@@ -46,11 +58,15 @@ function hashString(str, prefix, repeat = 3) {
46
58
  if (repeat === 1) {
47
59
  return result;
48
60
  } else {
49
- return hashString(result, prefix, repeat - 1);
61
+ return nanoHash(result, prefix, repeat - 1);
50
62
  }
51
63
  }
64
+
65
+ // src/main.ts
66
+ __dev_mode__: import_package_tracer.packageTracer.add("@alwatr/hash-string", "5.2.1");
52
67
  // Annotate the CommonJS export names for ESM import in node:
53
68
  0 && (module.exports = {
54
- hashString
69
+ djb2Hash,
70
+ nanoHash
55
71
  });
56
72
  //# sourceMappingURL=main.cjs.map
package/dist/main.cjs.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/main.ts"],
4
- "sourcesContent": ["import {packageTracer} from '@alwatr/package-tracer';\n\n__dev_mode__: packageTracer.add(__package_name__, __package_version__);\n\n/**\n * Simple hash string for fast hashing (like md5).\n * This function is not very secure and should not be used for security purposes.\n * But it cannot be reversed easily and brute force can take up to years for very fast computers.\n *\n * @param str - The string or number to hash\n * @param prefix - A prefix to add to the beginning of the hash result\n * @param repeat - Number of times to repeat the hashing process for increased complexity (default: 3)\n * @returns A hashed string with the specified prefix\n */\nexport function hashString(str: string | number, prefix: string, repeat = 3): string {\n if (repeat < 1) {\n throw new Error('The repeat parameter must be greater than or equal to 1');\n }\n\n let hash1 = 0xdeadbeef;\n let hash2 = 0x41c6ce57;\n\n if (typeof str === 'number') {\n str = str.toString();\n }\n\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash1 = Math.imul(hash1 ^ char, 2654435761);\n hash2 = Math.imul(hash2 ^ char, 1597334677);\n }\n\n hash1 = Math.imul(hash1 ^ (hash1 >>> 16), 2246822507) ^ Math.imul(hash2 ^ (hash2 >>> 13), 3266489909);\n hash2 = Math.imul(hash2 ^ (hash2 >>> 16), 2246822507) ^ Math.imul(hash1 ^ (hash1 >>> 13), 3266489909);\n\n const result = prefix + (hash1 >>> 0).toString(36) + (hash2 >>> 0).toString(36);\n if (repeat === 1) {\n return result;\n }\n else {\n return hashString(result, prefix, repeat - 1);\n }\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAA4B;AAE5B,aAAc,qCAAc,IAAI,uBAAkB,OAAmB;AAY9D,SAAS,WAAW,KAAsB,QAAgB,SAAS,GAAW;AACnF,MAAI,SAAS,GAAG;AACd,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AAEA,MAAI,QAAQ;AACZ,MAAI,QAAQ;AAEZ,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,IAAI,SAAS;AAAA,EACrB;AAEA,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAM,OAAO,IAAI,WAAW,CAAC;AAC7B,YAAQ,KAAK,KAAK,QAAQ,MAAM,UAAU;AAC1C,YAAQ,KAAK,KAAK,QAAQ,MAAM,UAAU;AAAA,EAC5C;AAEA,UAAQ,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU,IAAI,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU;AACpG,UAAQ,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU,IAAI,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU;AAEpG,QAAM,SAAS,UAAU,UAAU,GAAG,SAAS,EAAE,KAAK,UAAU,GAAG,SAAS,EAAE;AAC9E,MAAI,WAAW,GAAG;AAChB,WAAO;AAAA,EACT,OACK;AACH,WAAO,WAAW,QAAQ,QAAQ,SAAS,CAAC;AAAA,EAC9C;AACF;",
3
+ "sources": ["../src/main.ts", "../src/djb2-hash.ts", "../src/nano-hash.ts"],
4
+ "sourcesContent": ["import {packageTracer} from '@alwatr/package-tracer';\n\n__dev_mode__: packageTracer.add(__package_name__, __package_version__);\n\nexport * from './djb2-hash.js';\nexport * from './nano-hash.js';\n", "/**\n * DJB2 Hash Algorithm - A fast string hashing function.\n *\n * This implementation is based on Daniel J. Bernstein's popular 'times 33' hash algorithm,\n * commonly known as DJB2. It's known for its simplicity, speed, and good distribution properties\n * for short strings, making it suitable for general purpose hashing needs.\n *\n * Performance notes:\n * - Uses right-to-left iteration to avoid repeated length lookups\n * - Employs bit shifting operations for faster computation\n * - Final right shift ensures unsigned 32-bit integer output\n *\n * @param {string} str - The input string to be hashed\n * @returns {number} A 32-bit unsigned integer hash value\n *\n * @example\n * // Returns a numeric hash value\n * const hashValue = djb2Hash(\"hello world\");\n */\nexport function djb2Hash(str: string): number {\n // 5381 is a prime number used as initial value in the DJB2 algorithm\n let hashValue = 5381;\n\n // Reverse loop for better performance - avoids repeated length property lookup\n for (let i = str.length - 1; i >= 0; i--) {\n // Using left shift (*2) and addition instead of multiplication by 33\n // (hash * 33) is equivalent to ((hash << 5) + hash)\n hashValue = ((hashValue << 5) + hashValue) ^ str.charCodeAt(i);\n }\n\n return hashValue >>> 0;\n}\n", "/**\n * Simple hash string for fast hashing (like md5).\n * This function is not very secure and should not be used for security purposes.\n * But it cannot be reversed easily and brute force can take up to years for fast computers.\n *\n * @param str - The string or number to hash\n * @param prefix - A prefix to add to the beginning of the hash result\n * @param repeat - Number of times to repeat the hashing process for increased complexity (default: 3)\n * @returns A hashed string with the specified prefix\n */\nexport function nanoHash(str: string | number, prefix: string, repeat = 1): string {\n if (repeat < 1) {\n throw new Error('The repeat parameter must be greater than or equal to 1');\n }\n\n let hash1 = 0xdeadbeef;\n let hash2 = 0x41c6ce57;\n\n if (typeof str === 'number') {\n str = str.toString();\n }\n\n const len = str.length;\n for (let i = 0; i < len; i++) {\n const char = str.charCodeAt(i);\n hash1 = Math.imul(hash1 ^ char, 2654435761);\n hash2 = Math.imul(hash2 ^ char, 1597334677);\n }\n\n hash1 = Math.imul(hash1 ^ (hash1 >>> 16), 2246822507) ^ Math.imul(hash2 ^ (hash2 >>> 13), 3266489909);\n hash2 = Math.imul(hash2 ^ (hash2 >>> 16), 2246822507) ^ Math.imul(hash1 ^ (hash1 >>> 13), 3266489909);\n\n const result = prefix + (hash1 >>> 0).toString(36) + (hash2 >>> 0).toString(36);\n if (repeat === 1) {\n return result;\n }\n else {\n return nanoHash(result, prefix, repeat - 1);\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAA4B;;;ACmBrB,SAAS,SAAS,KAAqB;AAE5C,MAAI,YAAY;AAGhB,WAAS,IAAI,IAAI,SAAS,GAAG,KAAK,GAAG,KAAK;AAGxC,iBAAc,aAAa,KAAK,YAAa,IAAI,WAAW,CAAC;AAAA,EAC/D;AAEA,SAAO,cAAc;AACvB;;;ACrBO,SAAS,SAAS,KAAsB,QAAgB,SAAS,GAAW;AACjF,MAAI,SAAS,GAAG;AACd,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AAEA,MAAI,QAAQ;AACZ,MAAI,QAAQ;AAEZ,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,IAAI,SAAS;AAAA,EACrB;AAEA,QAAM,MAAM,IAAI;AAChB,WAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,UAAM,OAAO,IAAI,WAAW,CAAC;AAC7B,YAAQ,KAAK,KAAK,QAAQ,MAAM,UAAU;AAC1C,YAAQ,KAAK,KAAK,QAAQ,MAAM,UAAU;AAAA,EAC5C;AAEA,UAAQ,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU,IAAI,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU;AACpG,UAAQ,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU,IAAI,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU;AAEpG,QAAM,SAAS,UAAU,UAAU,GAAG,SAAS,EAAE,KAAK,UAAU,GAAG,SAAS,EAAE;AAC9E,MAAI,WAAW,GAAG;AAChB,WAAO;AAAA,EACT,OACK;AACH,WAAO,SAAS,QAAQ,QAAQ,SAAS,CAAC;AAAA,EAC5C;AACF;;;AFrCA,aAAc,qCAAc,IAAI,uBAAkB,OAAmB;",
6
6
  "names": []
7
7
  }
package/dist/main.d.ts CHANGED
@@ -1,12 +1,3 @@
1
- /**
2
- * Simple hash string for fast hashing (like md5).
3
- * This function is not very secure and should not be used for security purposes.
4
- * But it cannot be reversed easily and brute force can take up to years for very fast computers.
5
- *
6
- * @param str - The string or number to hash
7
- * @param prefix - A prefix to add to the beginning of the hash result
8
- * @param repeat - Number of times to repeat the hashing process for increased complexity (default: 3)
9
- * @returns A hashed string with the specified prefix
10
- */
11
- export declare function hashString(str: string | number, prefix: string, repeat?: number): string;
1
+ export * from './djb2-hash.js';
2
+ export * from './nano-hash.js';
12
3
  //# sourceMappingURL=main.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,MAAM,CA4BnF"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAIA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC"}
package/dist/main.mjs CHANGED
@@ -1,9 +1,19 @@
1
- /* @alwatr/hash-string v5.1.0 */
1
+ /* @alwatr/hash-string v5.2.1 */
2
2
 
3
3
  // src/main.ts
4
4
  import { packageTracer } from "@alwatr/package-tracer";
5
- __dev_mode__: packageTracer.add("@alwatr/hash-string", "5.1.0");
6
- function hashString(str, prefix, repeat = 3) {
5
+
6
+ // src/djb2-hash.ts
7
+ function djb2Hash(str) {
8
+ let hashValue = 5381;
9
+ for (let i = str.length - 1; i >= 0; i--) {
10
+ hashValue = (hashValue << 5) + hashValue ^ str.charCodeAt(i);
11
+ }
12
+ return hashValue >>> 0;
13
+ }
14
+
15
+ // src/nano-hash.ts
16
+ function nanoHash(str, prefix, repeat = 1) {
7
17
  if (repeat < 1) {
8
18
  throw new Error("The repeat parameter must be greater than or equal to 1");
9
19
  }
@@ -12,7 +22,8 @@ function hashString(str, prefix, repeat = 3) {
12
22
  if (typeof str === "number") {
13
23
  str = str.toString();
14
24
  }
15
- for (let i = 0; i < str.length; i++) {
25
+ const len = str.length;
26
+ for (let i = 0; i < len; i++) {
16
27
  const char = str.charCodeAt(i);
17
28
  hash1 = Math.imul(hash1 ^ char, 2654435761);
18
29
  hash2 = Math.imul(hash2 ^ char, 1597334677);
@@ -23,10 +34,14 @@ function hashString(str, prefix, repeat = 3) {
23
34
  if (repeat === 1) {
24
35
  return result;
25
36
  } else {
26
- return hashString(result, prefix, repeat - 1);
37
+ return nanoHash(result, prefix, repeat - 1);
27
38
  }
28
39
  }
40
+
41
+ // src/main.ts
42
+ __dev_mode__: packageTracer.add("@alwatr/hash-string", "5.2.1");
29
43
  export {
30
- hashString
44
+ djb2Hash,
45
+ nanoHash
31
46
  };
32
47
  //# sourceMappingURL=main.mjs.map
package/dist/main.mjs.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/main.ts"],
4
- "sourcesContent": ["import {packageTracer} from '@alwatr/package-tracer';\n\n__dev_mode__: packageTracer.add(__package_name__, __package_version__);\n\n/**\n * Simple hash string for fast hashing (like md5).\n * This function is not very secure and should not be used for security purposes.\n * But it cannot be reversed easily and brute force can take up to years for very fast computers.\n *\n * @param str - The string or number to hash\n * @param prefix - A prefix to add to the beginning of the hash result\n * @param repeat - Number of times to repeat the hashing process for increased complexity (default: 3)\n * @returns A hashed string with the specified prefix\n */\nexport function hashString(str: string | number, prefix: string, repeat = 3): string {\n if (repeat < 1) {\n throw new Error('The repeat parameter must be greater than or equal to 1');\n }\n\n let hash1 = 0xdeadbeef;\n let hash2 = 0x41c6ce57;\n\n if (typeof str === 'number') {\n str = str.toString();\n }\n\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash1 = Math.imul(hash1 ^ char, 2654435761);\n hash2 = Math.imul(hash2 ^ char, 1597334677);\n }\n\n hash1 = Math.imul(hash1 ^ (hash1 >>> 16), 2246822507) ^ Math.imul(hash2 ^ (hash2 >>> 13), 3266489909);\n hash2 = Math.imul(hash2 ^ (hash2 >>> 16), 2246822507) ^ Math.imul(hash1 ^ (hash1 >>> 13), 3266489909);\n\n const result = prefix + (hash1 >>> 0).toString(36) + (hash2 >>> 0).toString(36);\n if (repeat === 1) {\n return result;\n }\n else {\n return hashString(result, prefix, repeat - 1);\n }\n}\n"],
5
- "mappings": ";;;AAAA,SAAQ,qBAAoB;AAE5B,aAAc,eAAc,IAAI,uBAAkB,OAAmB;AAY9D,SAAS,WAAW,KAAsB,QAAgB,SAAS,GAAW;AACnF,MAAI,SAAS,GAAG;AACd,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AAEA,MAAI,QAAQ;AACZ,MAAI,QAAQ;AAEZ,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,IAAI,SAAS;AAAA,EACrB;AAEA,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAM,OAAO,IAAI,WAAW,CAAC;AAC7B,YAAQ,KAAK,KAAK,QAAQ,MAAM,UAAU;AAC1C,YAAQ,KAAK,KAAK,QAAQ,MAAM,UAAU;AAAA,EAC5C;AAEA,UAAQ,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU,IAAI,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU;AACpG,UAAQ,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU,IAAI,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU;AAEpG,QAAM,SAAS,UAAU,UAAU,GAAG,SAAS,EAAE,KAAK,UAAU,GAAG,SAAS,EAAE;AAC9E,MAAI,WAAW,GAAG;AAChB,WAAO;AAAA,EACT,OACK;AACH,WAAO,WAAW,QAAQ,QAAQ,SAAS,CAAC;AAAA,EAC9C;AACF;",
3
+ "sources": ["../src/main.ts", "../src/djb2-hash.ts", "../src/nano-hash.ts"],
4
+ "sourcesContent": ["import {packageTracer} from '@alwatr/package-tracer';\n\n__dev_mode__: packageTracer.add(__package_name__, __package_version__);\n\nexport * from './djb2-hash.js';\nexport * from './nano-hash.js';\n", "/**\n * DJB2 Hash Algorithm - A fast string hashing function.\n *\n * This implementation is based on Daniel J. Bernstein's popular 'times 33' hash algorithm,\n * commonly known as DJB2. It's known for its simplicity, speed, and good distribution properties\n * for short strings, making it suitable for general purpose hashing needs.\n *\n * Performance notes:\n * - Uses right-to-left iteration to avoid repeated length lookups\n * - Employs bit shifting operations for faster computation\n * - Final right shift ensures unsigned 32-bit integer output\n *\n * @param {string} str - The input string to be hashed\n * @returns {number} A 32-bit unsigned integer hash value\n *\n * @example\n * // Returns a numeric hash value\n * const hashValue = djb2Hash(\"hello world\");\n */\nexport function djb2Hash(str: string): number {\n // 5381 is a prime number used as initial value in the DJB2 algorithm\n let hashValue = 5381;\n\n // Reverse loop for better performance - avoids repeated length property lookup\n for (let i = str.length - 1; i >= 0; i--) {\n // Using left shift (*2) and addition instead of multiplication by 33\n // (hash * 33) is equivalent to ((hash << 5) + hash)\n hashValue = ((hashValue << 5) + hashValue) ^ str.charCodeAt(i);\n }\n\n return hashValue >>> 0;\n}\n", "/**\n * Simple hash string for fast hashing (like md5).\n * This function is not very secure and should not be used for security purposes.\n * But it cannot be reversed easily and brute force can take up to years for fast computers.\n *\n * @param str - The string or number to hash\n * @param prefix - A prefix to add to the beginning of the hash result\n * @param repeat - Number of times to repeat the hashing process for increased complexity (default: 3)\n * @returns A hashed string with the specified prefix\n */\nexport function nanoHash(str: string | number, prefix: string, repeat = 1): string {\n if (repeat < 1) {\n throw new Error('The repeat parameter must be greater than or equal to 1');\n }\n\n let hash1 = 0xdeadbeef;\n let hash2 = 0x41c6ce57;\n\n if (typeof str === 'number') {\n str = str.toString();\n }\n\n const len = str.length;\n for (let i = 0; i < len; i++) {\n const char = str.charCodeAt(i);\n hash1 = Math.imul(hash1 ^ char, 2654435761);\n hash2 = Math.imul(hash2 ^ char, 1597334677);\n }\n\n hash1 = Math.imul(hash1 ^ (hash1 >>> 16), 2246822507) ^ Math.imul(hash2 ^ (hash2 >>> 13), 3266489909);\n hash2 = Math.imul(hash2 ^ (hash2 >>> 16), 2246822507) ^ Math.imul(hash1 ^ (hash1 >>> 13), 3266489909);\n\n const result = prefix + (hash1 >>> 0).toString(36) + (hash2 >>> 0).toString(36);\n if (repeat === 1) {\n return result;\n }\n else {\n return nanoHash(result, prefix, repeat - 1);\n }\n}\n"],
5
+ "mappings": ";;;AAAA,SAAQ,qBAAoB;;;ACmBrB,SAAS,SAAS,KAAqB;AAE5C,MAAI,YAAY;AAGhB,WAAS,IAAI,IAAI,SAAS,GAAG,KAAK,GAAG,KAAK;AAGxC,iBAAc,aAAa,KAAK,YAAa,IAAI,WAAW,CAAC;AAAA,EAC/D;AAEA,SAAO,cAAc;AACvB;;;ACrBO,SAAS,SAAS,KAAsB,QAAgB,SAAS,GAAW;AACjF,MAAI,SAAS,GAAG;AACd,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AAEA,MAAI,QAAQ;AACZ,MAAI,QAAQ;AAEZ,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,IAAI,SAAS;AAAA,EACrB;AAEA,QAAM,MAAM,IAAI;AAChB,WAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,UAAM,OAAO,IAAI,WAAW,CAAC;AAC7B,YAAQ,KAAK,KAAK,QAAQ,MAAM,UAAU;AAC1C,YAAQ,KAAK,KAAK,QAAQ,MAAM,UAAU;AAAA,EAC5C;AAEA,UAAQ,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU,IAAI,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU;AACpG,UAAQ,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU,IAAI,KAAK,KAAK,QAAS,UAAU,IAAK,UAAU;AAEpG,QAAM,SAAS,UAAU,UAAU,GAAG,SAAS,EAAE,KAAK,UAAU,GAAG,SAAS,EAAE;AAC9E,MAAI,WAAW,GAAG;AAChB,WAAO;AAAA,EACT,OACK;AACH,WAAO,SAAS,QAAQ,QAAQ,SAAS,CAAC;AAAA,EAC5C;AACF;;;AFrCA,aAAc,eAAc,IAAI,uBAAkB,OAAmB;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Simple hash string for fast hashing (like md5).
3
+ * This function is not very secure and should not be used for security purposes.
4
+ * But it cannot be reversed easily and brute force can take up to years for fast computers.
5
+ *
6
+ * @param str - The string or number to hash
7
+ * @param prefix - A prefix to add to the beginning of the hash result
8
+ * @param repeat - Number of times to repeat the hashing process for increased complexity (default: 3)
9
+ * @returns A hashed string with the specified prefix
10
+ */
11
+ export declare function nanoHash(str: string | number, prefix: string, repeat?: number): string;
12
+ //# sourceMappingURL=nano-hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nano-hash.d.ts","sourceRoot":"","sources":["../src/nano-hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,MAAM,CA6BjF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alwatr/hash-string",
3
- "version": "5.1.0",
3
+ "version": "5.2.1",
4
4
  "description": "A simple utility to generate a hash string.",
5
5
  "author": "S. Ali Mihandoost <ali.mihandoost@gmail.com>",
6
6
  "keywords": [
@@ -71,14 +71,14 @@
71
71
  "clean": "rm -rfv dist *.tsbuildinfo"
72
72
  },
73
73
  "dependencies": {
74
- "@alwatr/package-tracer": "^5.5.1"
74
+ "@alwatr/package-tracer": "^5.5.3"
75
75
  },
76
76
  "devDependencies": {
77
- "@alwatr/nano-build": "^5.5.1",
77
+ "@alwatr/nano-build": "^5.5.3",
78
78
  "@alwatr/prettier-config": "^5.0.0",
79
79
  "@alwatr/tsconfig-base": "^5.0.0",
80
80
  "jest": "^29.7.0",
81
- "typescript": "^5.8.2"
81
+ "typescript": "^5.8.3"
82
82
  },
83
- "gitHead": "21cb1fe0f26a580944d9e72a313fc99308cd8be7"
83
+ "gitHead": "424a7a3e08e5f10fcfe53440d1cead68c88baf32"
84
84
  }
@@ -0,0 +1,72 @@
1
+ import {djb2Hash} from '@alwatr/hash-string';
2
+
3
+ describe('djb2Hash', () => {
4
+ it('should generate numeric hash values for string inputs', () => {
5
+ const result = djb2Hash('test');
6
+ expect(typeof result).toBe('number');
7
+ expect(Number.isInteger(result)).toBe(true);
8
+ });
9
+
10
+ it('should return different hashes for different inputs', () => {
11
+ const hash1 = djb2Hash('test1');
12
+ const hash2 = djb2Hash('test2');
13
+ expect(hash1).not.toBe(hash2);
14
+ });
15
+
16
+ it('should generate consistent hashes for the same input', () => {
17
+ const input = 'consistencyTest';
18
+ const hash1 = djb2Hash(input);
19
+ const hash2 = djb2Hash(input);
20
+ expect(hash1).toBe(hash2);
21
+ });
22
+
23
+ it('should handle empty strings', () => {
24
+ const result = djb2Hash('');
25
+ expect(typeof result).toBe('number');
26
+ // The hash for an empty string should be the initial value right-shifted by 0
27
+ expect(result).toBe(5381 >>> 0);
28
+ });
29
+
30
+ it('should handle special characters', () => {
31
+ const result = djb2Hash('!@#$%^&*()');
32
+ expect(typeof result).toBe('number');
33
+ expect(Number.isInteger(result)).toBe(true);
34
+ });
35
+
36
+ it('should handle long strings', () => {
37
+ const longString = 'a'.repeat(1000);
38
+ const result = djb2Hash(longString);
39
+ expect(typeof result).toBe('number');
40
+ expect(Number.isInteger(result)).toBe(true);
41
+ });
42
+
43
+ it('should handle Unicode characters', () => {
44
+ const unicodeString = '😀🌍🚀';
45
+ const result = djb2Hash(unicodeString);
46
+ expect(typeof result).toBe('number');
47
+ expect(Number.isInteger(result)).toBe(true);
48
+ });
49
+
50
+ it('should produce 32-bit unsigned integer outputs', () => {
51
+ const inputs = ['test', 'hello world', 'unicode 😀', 'a'.repeat(1000)];
52
+
53
+ for (const input of inputs) {
54
+ const result = djb2Hash(input);
55
+ expect(result).toBeLessThanOrEqual(0xFFFFFFFF); // Max 32-bit unsigned int
56
+ expect(result).toBeGreaterThanOrEqual(0);
57
+ }
58
+ });
59
+
60
+ it('should produce deterministic results', () => {
61
+ // Test with known hash values
62
+ expect(djb2Hash('hello')).toBe(181380007);
63
+ expect(djb2Hash('world')).toBe(164394279);
64
+ expect(djb2Hash('hello world')).toBe(2616892229);
65
+ expect(djb2Hash('')).toBe(5381);
66
+ });
67
+
68
+ it('should handle case sensitivity', () => {
69
+ expect(djb2Hash('Hello')).not.toBe(djb2Hash('hello'));
70
+ expect(djb2Hash('WORLD')).not.toBe(djb2Hash('world'));
71
+ });
72
+ });
@@ -1,22 +1,22 @@
1
- import {hashString} from '@alwatr/hash-string';
1
+ import {nanoHash} from '@alwatr/hash-string';
2
2
 
3
3
  describe('hashString', () => {
4
4
  it('should generate hash for string inputs', () => {
5
- const result = hashString('test', 'prefix-');
5
+ const result = nanoHash('test', 'prefix-');
6
6
  expect(typeof result).toBe('string');
7
7
  expect(result.startsWith('prefix-')).toBe(true);
8
8
  expect(result).not.toBe('prefix-test');
9
9
  });
10
10
 
11
11
  it('should generate hash for numeric inputs', () => {
12
- const result = hashString(12345, 'num-');
12
+ const result = nanoHash(12345, 'num-');
13
13
  expect(typeof result).toBe('string');
14
14
  expect(result.startsWith('num-')).toBe(true);
15
15
  });
16
16
 
17
17
  it('should return different hashes for different inputs', () => {
18
- const hash1 = hashString('test1', 'p-');
19
- const hash2 = hashString('test2', 'p-');
18
+ const hash1 = nanoHash('test1', 'p-');
19
+ const hash2 = nanoHash('test2', 'p-');
20
20
  expect(hash1).not.toBe(hash2);
21
21
  });
22
22
 
@@ -24,7 +24,7 @@ describe('hashString', () => {
24
24
  const prefixes = ['a-', 'test-', 'hash_', '123-'];
25
25
 
26
26
  prefixes.forEach((prefix) => {
27
- const result = hashString('sameInput', prefix);
27
+ const result = nanoHash('sameInput', prefix);
28
28
  expect(result.startsWith(prefix)).toBe(true);
29
29
  });
30
30
  });
@@ -33,9 +33,9 @@ describe('hashString', () => {
33
33
  const input = 'repeatTest';
34
34
  const prefix = 'r-';
35
35
 
36
- const hash1 = hashString(input, prefix, 1);
37
- const hash2 = hashString(input, prefix, 2);
38
- const hash3 = hashString(input, prefix, 3);
36
+ const hash1 = nanoHash(input, prefix, 1);
37
+ const hash2 = nanoHash(input, prefix, 2);
38
+ const hash3 = nanoHash(input, prefix, 3);
39
39
 
40
40
  expect(hash1).not.toBe(hash2);
41
41
  expect(hash2).not.toBe(hash3);
@@ -43,14 +43,14 @@ describe('hashString', () => {
43
43
  });
44
44
 
45
45
  it('should handle empty strings', () => {
46
- const result = hashString('', 'empty-');
46
+ const result = nanoHash('', 'empty-');
47
47
  expect(typeof result).toBe('string');
48
48
  expect(result.startsWith('empty-')).toBe(true);
49
49
  expect(result.length).toBeGreaterThan('empty-'.length);
50
50
  });
51
51
 
52
52
  it('should handle special characters', () => {
53
- const result = hashString('!@#$%^&*()', 'special-');
53
+ const result = nanoHash('!@#$%^&*()', 'special-');
54
54
  expect(typeof result).toBe('string');
55
55
  expect(result.startsWith('special-')).toBe(true);
56
56
  });
@@ -59,15 +59,15 @@ describe('hashString', () => {
59
59
  const input = 'consistencyTest';
60
60
  const prefix = 'c-';
61
61
 
62
- const hash1 = hashString(input, prefix);
63
- const hash2 = hashString(input, prefix);
62
+ const hash1 = nanoHash(input, prefix);
63
+ const hash2 = nanoHash(input, prefix);
64
64
 
65
65
  expect(hash1).toBe(hash2);
66
66
  });
67
67
 
68
68
  it('should handle long strings', () => {
69
69
  const longString = 'a'.repeat(1000);
70
- const result = hashString(longString, 'long-');
70
+ const result = nanoHash(longString, 'long-');
71
71
 
72
72
  expect(typeof result).toBe('string');
73
73
  expect(result.startsWith('long-')).toBe(true);
@@ -75,19 +75,27 @@ describe('hashString', () => {
75
75
 
76
76
  it('should handle Unicode characters', () => {
77
77
  const unicodeString = '😀🌍🚀';
78
- const result = hashString(unicodeString, 'unicode-');
78
+ const result = nanoHash(unicodeString, 'unicode-');
79
79
 
80
80
  expect(typeof result).toBe('string');
81
81
  expect(result.startsWith('unicode-')).toBe(true);
82
82
  });
83
83
 
84
- it('should default to repeat value of 3 when not specified', () => {
84
+ it('should default to repeat value of 1 when not specified', () => {
85
85
  const input = 'defaultRepeat';
86
86
  const prefix = 'd-';
87
87
 
88
- const defaultResult = hashString(input, prefix);
89
- const explicitResult = hashString(input, prefix, 3);
88
+ const defaultResult = nanoHash(input, prefix);
89
+ const explicitResult = nanoHash(input, prefix, 1);
90
90
 
91
91
  expect(defaultResult).toBe(explicitResult);
92
92
  });
93
+
94
+ it('should algorithm be deterministic', () => {
95
+ const input = 'Ali@MD_65';
96
+ const prefix = 'p-';
97
+ const expectedHash = 'p-dm3wzfp6jiud';
98
+ const hash = nanoHash(input, prefix, 3);
99
+ expect(hash).toBe(expectedHash);
100
+ });
93
101
  });