@xylabs/hex 2.13.10
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/LICENSE +165 -0
- package/README.md +69 -0
- package/dist/browser/address.d.cts +9 -0
- package/dist/browser/address.d.cts.map +1 -0
- package/dist/browser/address.d.mts +9 -0
- package/dist/browser/address.d.mts.map +1 -0
- package/dist/browser/address.d.ts +9 -0
- package/dist/browser/address.d.ts.map +1 -0
- package/dist/browser/assert.d.cts +4 -0
- package/dist/browser/assert.d.cts.map +1 -0
- package/dist/browser/assert.d.mts +4 -0
- package/dist/browser/assert.d.mts.map +1 -0
- package/dist/browser/assert.d.ts +4 -0
- package/dist/browser/assert.d.ts.map +1 -0
- package/dist/browser/hash.d.cts +13 -0
- package/dist/browser/hash.d.cts.map +1 -0
- package/dist/browser/hash.d.mts +13 -0
- package/dist/browser/hash.d.mts.map +1 -0
- package/dist/browser/hash.d.ts +13 -0
- package/dist/browser/hash.d.ts.map +1 -0
- package/dist/browser/hex.d.cts +14 -0
- package/dist/browser/hex.d.cts.map +1 -0
- package/dist/browser/hex.d.mts +14 -0
- package/dist/browser/hex.d.mts.map +1 -0
- package/dist/browser/hex.d.ts +14 -0
- package/dist/browser/hex.d.ts.map +1 -0
- package/dist/browser/index.cjs +153 -0
- package/dist/browser/index.cjs.map +1 -0
- package/dist/browser/index.d.cts +4 -0
- package/dist/browser/index.d.cts.map +1 -0
- package/dist/browser/index.d.mts +4 -0
- package/dist/browser/index.d.mts.map +1 -0
- package/dist/browser/index.d.ts +4 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +130 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/node/address.d.cts +9 -0
- package/dist/node/address.d.cts.map +1 -0
- package/dist/node/address.d.mts +9 -0
- package/dist/node/address.d.mts.map +1 -0
- package/dist/node/address.d.ts +9 -0
- package/dist/node/address.d.ts.map +1 -0
- package/dist/node/assert.d.cts +4 -0
- package/dist/node/assert.d.cts.map +1 -0
- package/dist/node/assert.d.mts +4 -0
- package/dist/node/assert.d.mts.map +1 -0
- package/dist/node/assert.d.ts +4 -0
- package/dist/node/assert.d.ts.map +1 -0
- package/dist/node/hash.d.cts +13 -0
- package/dist/node/hash.d.cts.map +1 -0
- package/dist/node/hash.d.mts +13 -0
- package/dist/node/hash.d.mts.map +1 -0
- package/dist/node/hash.d.ts +13 -0
- package/dist/node/hash.d.ts.map +1 -0
- package/dist/node/hex.d.cts +14 -0
- package/dist/node/hex.d.cts.map +1 -0
- package/dist/node/hex.d.mts +14 -0
- package/dist/node/hex.d.mts.map +1 -0
- package/dist/node/hex.d.ts +14 -0
- package/dist/node/hex.d.ts.map +1 -0
- package/dist/node/index.cjs +172 -0
- package/dist/node/index.cjs.map +1 -0
- package/dist/node/index.d.cts +4 -0
- package/dist/node/index.d.cts.map +1 -0
- package/dist/node/index.d.mts +4 -0
- package/dist/node/index.d.mts.map +1 -0
- package/dist/node/index.d.ts +4 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +130 -0
- package/dist/node/index.js.map +1 -0
- package/package.json +56 -0
- package/src/address.ts +33 -0
- package/src/assert.ts +13 -0
- package/src/hash.ts +37 -0
- package/src/hex.ts +80 -0
- package/src/index.ts +3 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// src/assert.ts
|
|
2
|
+
var assertError = (value, assert, defaultMessage) => {
|
|
3
|
+
if (assert) {
|
|
4
|
+
const assertString = typeof assert === "string" ? assert : typeof assert === "boolean" ? defaultMessage : assert(value, defaultMessage);
|
|
5
|
+
if (assertString) {
|
|
6
|
+
throw Error(assertString === true ? defaultMessage : assertString);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return void 0;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/hex.ts
|
|
13
|
+
var hexRegex = /^[0-9a-f]+$/i;
|
|
14
|
+
var hexRegexWithPrefix = /0x[0-9a-f]+$/i;
|
|
15
|
+
var hexFrom = (buffer) => {
|
|
16
|
+
return [...new Uint8Array(buffer)].map((x) => x.toString(16).padStart(2, "0")).join("");
|
|
17
|
+
};
|
|
18
|
+
var bitsToOctets = (value) => {
|
|
19
|
+
const octets = value >> 2;
|
|
20
|
+
if (value !== octets << 2)
|
|
21
|
+
throw Error("Bits for octets must multiple of 8");
|
|
22
|
+
return octets;
|
|
23
|
+
};
|
|
24
|
+
var octetsToBits = (value) => {
|
|
25
|
+
return value << 2;
|
|
26
|
+
};
|
|
27
|
+
var isRoundOctet = (value) => {
|
|
28
|
+
return value >> 2 << 2 === value;
|
|
29
|
+
};
|
|
30
|
+
var isHex = (value, bitLength) => {
|
|
31
|
+
if (typeof value !== "string")
|
|
32
|
+
return false;
|
|
33
|
+
if (bitLength !== void 0 && value.length !== bitsToOctets(bitLength))
|
|
34
|
+
return false;
|
|
35
|
+
return hexRegex.test(value);
|
|
36
|
+
};
|
|
37
|
+
function asHex(value, assertOrBitLength, assertOnly) {
|
|
38
|
+
const bitLength = typeof assertOrBitLength === "number" ? assertOrBitLength : void 0;
|
|
39
|
+
const assert = typeof assertOrBitLength !== "number" ? assertOrBitLength : assertOnly;
|
|
40
|
+
let stringValue = void 0;
|
|
41
|
+
switch (typeof value) {
|
|
42
|
+
case "string":
|
|
43
|
+
stringValue = hexRegexWithPrefix.test(value) ? value.substring(2) : value;
|
|
44
|
+
break;
|
|
45
|
+
case "number":
|
|
46
|
+
if (value === Math.floor(value)) {
|
|
47
|
+
stringValue = value.toString(16);
|
|
48
|
+
} else {
|
|
49
|
+
return assertError(value, assert, "Numbers must be whole");
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
case "bigint":
|
|
53
|
+
stringValue = value.toString(16);
|
|
54
|
+
break;
|
|
55
|
+
case "object":
|
|
56
|
+
if (value instanceof ArrayBuffer) {
|
|
57
|
+
stringValue = hexFrom(value);
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
60
|
+
default:
|
|
61
|
+
return assertError(value, assert, `Unsupported type [${typeof value}]`);
|
|
62
|
+
}
|
|
63
|
+
if (stringValue && bitLength) {
|
|
64
|
+
stringValue = stringValue.padStart(bitsToOctets(bitLength), "0");
|
|
65
|
+
}
|
|
66
|
+
return isHex(stringValue, bitLength) ? stringValue.toLowerCase() : assertError(value, assert, "Unable to convert to Hash");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/address.ts
|
|
70
|
+
var addressRegex = /0x[0-9a-f]+/i;
|
|
71
|
+
var isAddress = (value, bitLength = 160) => {
|
|
72
|
+
if (typeof value !== "string")
|
|
73
|
+
return false;
|
|
74
|
+
if (!addressRegex.test(value))
|
|
75
|
+
return false;
|
|
76
|
+
const valueHex = value.substring(2);
|
|
77
|
+
if (bitLength !== void 0 && valueHex.length !== bitsToOctets(bitLength))
|
|
78
|
+
return false;
|
|
79
|
+
return isHex(valueHex, bitLength);
|
|
80
|
+
};
|
|
81
|
+
function asAddress(value, assertOrBitLength, assertOnly) {
|
|
82
|
+
const bitLength = typeof assertOrBitLength === "number" ? assertOrBitLength : 160;
|
|
83
|
+
const assert = typeof assertOrBitLength !== "number" ? assertOrBitLength : assertOnly;
|
|
84
|
+
const result = `0x${asHex(value, bitLength, assert)}`;
|
|
85
|
+
return isAddress(result, bitLength) ? result : assertError(value, assert, "Resulting value is not an Address");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/hash.ts
|
|
89
|
+
var HashBitLength = [32, 64, 128, 256, 512, 1024, 2048, 4096];
|
|
90
|
+
var isHashBitLength = (value) => {
|
|
91
|
+
return typeof value === "number" && HashBitLength.includes(value);
|
|
92
|
+
};
|
|
93
|
+
var isHash = (value, bitLength = 256) => {
|
|
94
|
+
if (!isHex(value, bitLength))
|
|
95
|
+
return false;
|
|
96
|
+
const hex = asHex(value, bitLength);
|
|
97
|
+
if (!hex)
|
|
98
|
+
return false;
|
|
99
|
+
if (!isHashBitLength(octetsToBits(hex.length)))
|
|
100
|
+
return false;
|
|
101
|
+
return true;
|
|
102
|
+
};
|
|
103
|
+
var toHex = (buffer) => {
|
|
104
|
+
return [...new Uint8Array(buffer)].map((x) => x.toString(16).padStart(2, "0")).join("");
|
|
105
|
+
};
|
|
106
|
+
function asHash(value, assertOrBitLength, assertOnly) {
|
|
107
|
+
const bitLength = typeof assertOrBitLength === "number" ? assertOrBitLength : 256;
|
|
108
|
+
const assert = typeof assertOrBitLength !== "number" ? assertOrBitLength : assertOnly;
|
|
109
|
+
const result = asHex(value, bitLength, assert);
|
|
110
|
+
return isHash(result, bitLength) ? result : assertError(value, assert, "Resulting value is not a Hash");
|
|
111
|
+
}
|
|
112
|
+
export {
|
|
113
|
+
HashBitLength,
|
|
114
|
+
addressRegex,
|
|
115
|
+
asAddress,
|
|
116
|
+
asHash,
|
|
117
|
+
asHex,
|
|
118
|
+
bitsToOctets,
|
|
119
|
+
hexFrom,
|
|
120
|
+
hexRegex,
|
|
121
|
+
hexRegexWithPrefix,
|
|
122
|
+
isAddress,
|
|
123
|
+
isHash,
|
|
124
|
+
isHashBitLength,
|
|
125
|
+
isHex,
|
|
126
|
+
isRoundOctet,
|
|
127
|
+
octetsToBits,
|
|
128
|
+
toHex
|
|
129
|
+
};
|
|
130
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/assert.ts","../../src/hex.ts","../../src/address.ts","../../src/hash.ts"],"sourcesContent":["export type AssertCallback = (value: unknown, message: string) => string | boolean\n\nexport type AssertConfig = string | AssertCallback | boolean\n\nexport const assertError = (value: unknown, assert: AssertConfig | undefined, defaultMessage: string) => {\n if (assert) {\n const assertString = typeof assert === 'string' ? assert : typeof assert === 'boolean' ? defaultMessage : assert(value, defaultMessage)\n if (assertString) {\n throw Error(assertString === true ? defaultMessage : assertString)\n }\n }\n return undefined\n}\n","import { AssertConfig, assertError } from './assert'\n\nexport const hexRegex = /^[0-9a-f]+$/i\nexport const hexRegexWithPrefix = /0x[0-9a-f]+$/i\n\nexport type Hex = string\n\nexport const hexFrom = (buffer: ArrayBuffer) => {\n return [...new Uint8Array(buffer)].map((x) => x.toString(16).padStart(2, '0')).join('')\n}\n\n//determine the number of octets for a given number of bits\nexport const bitsToOctets = (value: number): number => {\n const octets = value >> 2\n if (value !== octets << 2) throw Error('Bits for octets must multiple of 8')\n return octets\n}\n\n//determine the number of octets for a given number of bits\nexport const octetsToBits = (value: number): number => {\n return value << 2\n}\n\n//are the number of bit a round octet (factor of 8)?\nexport const isRoundOctet = (value: number) => {\n return (value >> 2) << 2 === value\n}\n\nexport const isHex = (value: unknown, bitLength?: number): value is Hex => {\n //Is it a string?\n if (typeof value !== 'string') return false\n\n //If a bitLength specified, does it conform?\n if (bitLength !== undefined && value.length !== bitsToOctets(bitLength)) return false\n\n //Does it only has hex values?\n return hexRegex.test(value)\n}\n\nexport function asHex(value: unknown): Hex | undefined\nexport function asHex(value: unknown, bitLength?: number): Hex | undefined\nexport function asHex(value: unknown, assert: AssertConfig): Hex\nexport function asHex(value: unknown, bitLength: number | undefined, assert?: AssertConfig): Hex\nexport function asHex(value: unknown, assertOrBitLength?: AssertConfig | number, assertOnly?: AssertConfig): Hex | undefined {\n const bitLength = typeof assertOrBitLength === 'number' ? assertOrBitLength : undefined\n const assert = typeof assertOrBitLength !== 'number' ? assertOrBitLength : assertOnly\n\n let stringValue: string | undefined = undefined\n\n switch (typeof value) {\n case 'string':\n //remove the leading 0x if it is there\n stringValue = hexRegexWithPrefix.test(value) ? value.substring(2) : value\n break\n case 'number':\n if (value === Math.floor(value)) {\n stringValue = value.toString(16)\n } else {\n return assertError(value, assert, 'Numbers must be whole')\n }\n break\n case 'bigint':\n stringValue = value.toString(16)\n break\n case 'object':\n if (value instanceof ArrayBuffer) {\n stringValue = hexFrom(value)\n }\n break\n default:\n return assertError(value, assert, `Unsupported type [${typeof value}]`)\n }\n\n //make it conform to the bit length if shorter\n if (stringValue && bitLength) {\n stringValue = stringValue.padStart(bitsToOctets(bitLength), '0')\n }\n\n return isHex(stringValue, bitLength) ? stringValue.toLowerCase() : assertError(value, assert, 'Unable to convert to Hash')\n}\n","import { AssertConfig, assertError } from './assert'\nimport { asHex, bitsToOctets, isHex } from './hex'\n\nexport const addressRegex = /0x[0-9a-f]+/i\n\nexport type Address = string\n\nexport const isAddress = (value: unknown, bitLength = 160): value is Address => {\n //Is it a string?\n if (typeof value !== 'string') return false\n\n //Does it only has hex values and leading 0x?\n if (!addressRegex.test(value)) return false\n\n const valueHex = value.substring(2)\n\n //If a bitLength specified, does it conform?\n if (bitLength !== undefined && valueHex.length !== bitsToOctets(bitLength)) return false\n\n return isHex(valueHex, bitLength)\n}\n\nexport function asAddress(value: unknown): Address | undefined\nexport function asAddress(value: unknown, assert: AssertConfig): Address\nexport function asAddress(value: unknown, bitLength: number): Address | undefined\nexport function asAddress(value: unknown, bitLength: number, assert: AssertConfig): Address\nexport function asAddress(value: unknown, assertOrBitLength?: AssertConfig | number, assertOnly?: AssertConfig): Address | undefined {\n const bitLength = typeof assertOrBitLength === 'number' ? assertOrBitLength : 160\n const assert = typeof assertOrBitLength !== 'number' ? assertOrBitLength : assertOnly\n\n const result = `0x${asHex(value, bitLength, assert)}`\n return isAddress(result, bitLength) ? result : assertError(value, assert, 'Resulting value is not an Address')\n}\n","import { AssertConfig, assertError } from './assert'\nimport { asHex, Hex, isHex, octetsToBits } from './hex'\n\nexport type HashBitLength = 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096\nexport const HashBitLength: HashBitLength[] = [32, 64, 128, 256, 512, 1024, 2048, 4096]\n\nexport const isHashBitLength = (value: unknown): value is HashBitLength => {\n return typeof value === 'number' && HashBitLength.includes(value as HashBitLength)\n}\n\nexport type Hash = Hex\nexport const isHash = (value: unknown, bitLength: HashBitLength = 256): value is Hash => {\n if (!isHex(value, bitLength)) return false\n\n const hex = asHex(value, bitLength)\n if (!hex) return false\n\n if (!isHashBitLength(octetsToBits(hex.length))) return false\n\n return true\n}\n\nexport const toHex = (buffer: ArrayBuffer) => {\n return [...new Uint8Array(buffer)].map((x) => x.toString(16).padStart(2, '0')).join('')\n}\n\nexport function asHash(value: unknown): Hash | undefined\nexport function asHash(value: unknown, assert: AssertConfig): Hash\nexport function asHash(value: unknown, bitLength?: HashBitLength): Hash | undefined\nexport function asHash(value: unknown, bitLength: HashBitLength | undefined, assert: AssertConfig): Hash\nexport function asHash(value: unknown, assertOrBitLength?: AssertConfig | HashBitLength, assertOnly?: AssertConfig): Hash | undefined {\n const bitLength: HashBitLength = typeof assertOrBitLength === 'number' ? assertOrBitLength : 256\n const assert = typeof assertOrBitLength !== 'number' ? assertOrBitLength : assertOnly\n\n const result = asHex(value, bitLength, assert)\n return isHash(result, bitLength) ? result : assertError(value, assert, 'Resulting value is not a Hash')\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"license": "LGPL-3.0-only",
|
|
3
|
+
"name": "@xylabs/hex",
|
|
4
|
+
"author": {
|
|
5
|
+
"email": "support@xylabs.com",
|
|
6
|
+
"name": "XY Labs Development Team",
|
|
7
|
+
"url": "https://xylabs.com"
|
|
8
|
+
},
|
|
9
|
+
"bugs": {
|
|
10
|
+
"email": "support@xylabs.com",
|
|
11
|
+
"url": "https://github.com/xylabs/sdk-js/issues"
|
|
12
|
+
},
|
|
13
|
+
"workspaces": [
|
|
14
|
+
"packages/**/*"
|
|
15
|
+
],
|
|
16
|
+
"description": "Base functionality used throughout XY Labs TypeScript/JavaScript libraries",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"require": {
|
|
20
|
+
"types": "./dist/node/index.d.cts",
|
|
21
|
+
"default": "./dist/node/index.cjs"
|
|
22
|
+
},
|
|
23
|
+
"import": {
|
|
24
|
+
"types": "./dist/node/index.d.mts",
|
|
25
|
+
"default": "./dist/node/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"./package.json": "./package.json"
|
|
29
|
+
},
|
|
30
|
+
"main": "./dist/node/index.cjs",
|
|
31
|
+
"types": "./dist/node/index.d.ts",
|
|
32
|
+
"module": "./dist/node/index.js",
|
|
33
|
+
"homepage": "https://xylabs.com",
|
|
34
|
+
"keywords": [
|
|
35
|
+
"xylabs",
|
|
36
|
+
"utility",
|
|
37
|
+
"typescript",
|
|
38
|
+
"esm"
|
|
39
|
+
],
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@xylabs/ts-scripts-yarn3": "^3.2.8",
|
|
42
|
+
"@xylabs/tsconfig": "^3.2.8",
|
|
43
|
+
"typescript": "^5.3.2"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
},
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "https://github.com/xylabs/sdk-js.git"
|
|
51
|
+
},
|
|
52
|
+
"sideEffects": false,
|
|
53
|
+
"version": "2.13.10",
|
|
54
|
+
"packageManager": "yarn@3.3.1",
|
|
55
|
+
"type": "module"
|
|
56
|
+
}
|
package/src/address.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { AssertConfig, assertError } from './assert'
|
|
2
|
+
import { asHex, bitsToOctets, isHex } from './hex'
|
|
3
|
+
|
|
4
|
+
export const addressRegex = /0x[0-9a-f]+/i
|
|
5
|
+
|
|
6
|
+
export type Address = string
|
|
7
|
+
|
|
8
|
+
export const isAddress = (value: unknown, bitLength = 160): value is Address => {
|
|
9
|
+
//Is it a string?
|
|
10
|
+
if (typeof value !== 'string') return false
|
|
11
|
+
|
|
12
|
+
//Does it only has hex values and leading 0x?
|
|
13
|
+
if (!addressRegex.test(value)) return false
|
|
14
|
+
|
|
15
|
+
const valueHex = value.substring(2)
|
|
16
|
+
|
|
17
|
+
//If a bitLength specified, does it conform?
|
|
18
|
+
if (bitLength !== undefined && valueHex.length !== bitsToOctets(bitLength)) return false
|
|
19
|
+
|
|
20
|
+
return isHex(valueHex, bitLength)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function asAddress(value: unknown): Address | undefined
|
|
24
|
+
export function asAddress(value: unknown, assert: AssertConfig): Address
|
|
25
|
+
export function asAddress(value: unknown, bitLength: number): Address | undefined
|
|
26
|
+
export function asAddress(value: unknown, bitLength: number, assert: AssertConfig): Address
|
|
27
|
+
export function asAddress(value: unknown, assertOrBitLength?: AssertConfig | number, assertOnly?: AssertConfig): Address | undefined {
|
|
28
|
+
const bitLength = typeof assertOrBitLength === 'number' ? assertOrBitLength : 160
|
|
29
|
+
const assert = typeof assertOrBitLength !== 'number' ? assertOrBitLength : assertOnly
|
|
30
|
+
|
|
31
|
+
const result = `0x${asHex(value, bitLength, assert)}`
|
|
32
|
+
return isAddress(result, bitLength) ? result : assertError(value, assert, 'Resulting value is not an Address')
|
|
33
|
+
}
|
package/src/assert.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type AssertCallback = (value: unknown, message: string) => string | boolean
|
|
2
|
+
|
|
3
|
+
export type AssertConfig = string | AssertCallback | boolean
|
|
4
|
+
|
|
5
|
+
export const assertError = (value: unknown, assert: AssertConfig | undefined, defaultMessage: string) => {
|
|
6
|
+
if (assert) {
|
|
7
|
+
const assertString = typeof assert === 'string' ? assert : typeof assert === 'boolean' ? defaultMessage : assert(value, defaultMessage)
|
|
8
|
+
if (assertString) {
|
|
9
|
+
throw Error(assertString === true ? defaultMessage : assertString)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return undefined
|
|
13
|
+
}
|
package/src/hash.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { AssertConfig, assertError } from './assert'
|
|
2
|
+
import { asHex, Hex, isHex, octetsToBits } from './hex'
|
|
3
|
+
|
|
4
|
+
export type HashBitLength = 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096
|
|
5
|
+
export const HashBitLength: HashBitLength[] = [32, 64, 128, 256, 512, 1024, 2048, 4096]
|
|
6
|
+
|
|
7
|
+
export const isHashBitLength = (value: unknown): value is HashBitLength => {
|
|
8
|
+
return typeof value === 'number' && HashBitLength.includes(value as HashBitLength)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type Hash = Hex
|
|
12
|
+
export const isHash = (value: unknown, bitLength: HashBitLength = 256): value is Hash => {
|
|
13
|
+
if (!isHex(value, bitLength)) return false
|
|
14
|
+
|
|
15
|
+
const hex = asHex(value, bitLength)
|
|
16
|
+
if (!hex) return false
|
|
17
|
+
|
|
18
|
+
if (!isHashBitLength(octetsToBits(hex.length))) return false
|
|
19
|
+
|
|
20
|
+
return true
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const toHex = (buffer: ArrayBuffer) => {
|
|
24
|
+
return [...new Uint8Array(buffer)].map((x) => x.toString(16).padStart(2, '0')).join('')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function asHash(value: unknown): Hash | undefined
|
|
28
|
+
export function asHash(value: unknown, assert: AssertConfig): Hash
|
|
29
|
+
export function asHash(value: unknown, bitLength?: HashBitLength): Hash | undefined
|
|
30
|
+
export function asHash(value: unknown, bitLength: HashBitLength | undefined, assert: AssertConfig): Hash
|
|
31
|
+
export function asHash(value: unknown, assertOrBitLength?: AssertConfig | HashBitLength, assertOnly?: AssertConfig): Hash | undefined {
|
|
32
|
+
const bitLength: HashBitLength = typeof assertOrBitLength === 'number' ? assertOrBitLength : 256
|
|
33
|
+
const assert = typeof assertOrBitLength !== 'number' ? assertOrBitLength : assertOnly
|
|
34
|
+
|
|
35
|
+
const result = asHex(value, bitLength, assert)
|
|
36
|
+
return isHash(result, bitLength) ? result : assertError(value, assert, 'Resulting value is not a Hash')
|
|
37
|
+
}
|
package/src/hex.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { AssertConfig, assertError } from './assert'
|
|
2
|
+
|
|
3
|
+
export const hexRegex = /^[0-9a-f]+$/i
|
|
4
|
+
export const hexRegexWithPrefix = /0x[0-9a-f]+$/i
|
|
5
|
+
|
|
6
|
+
export type Hex = string
|
|
7
|
+
|
|
8
|
+
export const hexFrom = (buffer: ArrayBuffer) => {
|
|
9
|
+
return [...new Uint8Array(buffer)].map((x) => x.toString(16).padStart(2, '0')).join('')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//determine the number of octets for a given number of bits
|
|
13
|
+
export const bitsToOctets = (value: number): number => {
|
|
14
|
+
const octets = value >> 2
|
|
15
|
+
if (value !== octets << 2) throw Error('Bits for octets must multiple of 8')
|
|
16
|
+
return octets
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//determine the number of octets for a given number of bits
|
|
20
|
+
export const octetsToBits = (value: number): number => {
|
|
21
|
+
return value << 2
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//are the number of bit a round octet (factor of 8)?
|
|
25
|
+
export const isRoundOctet = (value: number) => {
|
|
26
|
+
return (value >> 2) << 2 === value
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const isHex = (value: unknown, bitLength?: number): value is Hex => {
|
|
30
|
+
//Is it a string?
|
|
31
|
+
if (typeof value !== 'string') return false
|
|
32
|
+
|
|
33
|
+
//If a bitLength specified, does it conform?
|
|
34
|
+
if (bitLength !== undefined && value.length !== bitsToOctets(bitLength)) return false
|
|
35
|
+
|
|
36
|
+
//Does it only has hex values?
|
|
37
|
+
return hexRegex.test(value)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function asHex(value: unknown): Hex | undefined
|
|
41
|
+
export function asHex(value: unknown, bitLength?: number): Hex | undefined
|
|
42
|
+
export function asHex(value: unknown, assert: AssertConfig): Hex
|
|
43
|
+
export function asHex(value: unknown, bitLength: number | undefined, assert?: AssertConfig): Hex
|
|
44
|
+
export function asHex(value: unknown, assertOrBitLength?: AssertConfig | number, assertOnly?: AssertConfig): Hex | undefined {
|
|
45
|
+
const bitLength = typeof assertOrBitLength === 'number' ? assertOrBitLength : undefined
|
|
46
|
+
const assert = typeof assertOrBitLength !== 'number' ? assertOrBitLength : assertOnly
|
|
47
|
+
|
|
48
|
+
let stringValue: string | undefined = undefined
|
|
49
|
+
|
|
50
|
+
switch (typeof value) {
|
|
51
|
+
case 'string':
|
|
52
|
+
//remove the leading 0x if it is there
|
|
53
|
+
stringValue = hexRegexWithPrefix.test(value) ? value.substring(2) : value
|
|
54
|
+
break
|
|
55
|
+
case 'number':
|
|
56
|
+
if (value === Math.floor(value)) {
|
|
57
|
+
stringValue = value.toString(16)
|
|
58
|
+
} else {
|
|
59
|
+
return assertError(value, assert, 'Numbers must be whole')
|
|
60
|
+
}
|
|
61
|
+
break
|
|
62
|
+
case 'bigint':
|
|
63
|
+
stringValue = value.toString(16)
|
|
64
|
+
break
|
|
65
|
+
case 'object':
|
|
66
|
+
if (value instanceof ArrayBuffer) {
|
|
67
|
+
stringValue = hexFrom(value)
|
|
68
|
+
}
|
|
69
|
+
break
|
|
70
|
+
default:
|
|
71
|
+
return assertError(value, assert, `Unsupported type [${typeof value}]`)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
//make it conform to the bit length if shorter
|
|
75
|
+
if (stringValue && bitLength) {
|
|
76
|
+
stringValue = stringValue.padStart(bitsToOctets(bitLength), '0')
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return isHex(stringValue, bitLength) ? stringValue.toLowerCase() : assertError(value, assert, 'Unable to convert to Hash')
|
|
80
|
+
}
|
package/src/index.ts
ADDED