@augment-vir/common 19.6.0 → 20.0.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/README.md CHANGED
@@ -3,3 +3,5 @@
3
3
  `augment-vir` is a collection of small helper functions that I constantly use across all my JavaScript and TypeScript repos. I call these functions `augments`. These are functions, constants, and types typically placed within a "util", or "helpers", etc. directory.
4
4
 
5
5
  This `common` package is for environment-agnostic augments. Everything in here will work in Node.js or the browser with identical results.
6
+
7
+ Note that the `random*` functions exported by this package will not work in Node.js < v19.0.0.
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.randomString = exports.createUuid = exports.randomBoolean = exports.randomInteger = void 0;
4
+ const common_number_1 = require("./common-number");
5
+ const crypto = globalThis.crypto;
6
+ // can't get this coverage to work
7
+ /* c8 ignore start */
8
+ /**
9
+ * Creates a random integer (decimal points are all cut off) between the given min and max
10
+ * (inclusive).
11
+ *
12
+ * This function uses cryptographically secure randomness.
13
+ */
14
+ function randomInteger({ min: rawMin, max: rawMax }) {
15
+ const { min, max } = (0, common_number_1.ensureMinAndMax)({ min: Math.floor(rawMin), max: Math.floor(rawMax) });
16
+ const range = max - min + 1;
17
+ const neededByteCount = Math.ceil(Math.log2(range) / 8);
18
+ const cutoff = Math.floor(256 ** neededByteCount / range) * range;
19
+ const currentBytes = new Uint8Array(neededByteCount);
20
+ let value;
21
+ do {
22
+ crypto.getRandomValues(currentBytes);
23
+ value = currentBytes.reduce((accum, byte, index) => {
24
+ return accum + byte * 256 ** index;
25
+ }, 0);
26
+ } while (value >= cutoff);
27
+ return min + (value % range);
28
+ }
29
+ exports.randomInteger = randomInteger;
30
+ /**
31
+ * Returns true at rate of the percentLikelyToBeTrue input. Inputs should be whole numbers which
32
+ * will be treated like percents. Anything outside of 0-100 inclusively will be clamped. An input 0
33
+ * will always return true. An input of 100 will always return true. Decimals on the input will be
34
+ * chopped off, use whole numbers.
35
+ *
36
+ * This function uses cryptographically secure randomness.
37
+ *
38
+ * @example
39
+ * randomBoolean(50); // 50% chance to return true
40
+ *
41
+ * @example
42
+ * randomBoolean(0); // always false, 0% chance of being true
43
+ *
44
+ * @example
45
+ * randomBoolean(100); // always true, 100% chance of being true
46
+ *
47
+ * @example
48
+ * randomBoolean(59.67; // 59% chance of being true
49
+ */
50
+ function randomBoolean(percentLikelyToBeTrue = 50) {
51
+ return (randomInteger({ min: 0, max: 99 }) <
52
+ (0, common_number_1.clamp)({
53
+ value: Math.floor(percentLikelyToBeTrue),
54
+ min: 0,
55
+ max: 100,
56
+ }));
57
+ }
58
+ exports.randomBoolean = randomBoolean;
59
+ /** Creates a cryptographically secure uuid. */
60
+ function createUuid() {
61
+ return crypto.randomUUID();
62
+ }
63
+ exports.createUuid = createUuid;
64
+ /**
65
+ * Creates a random string (including letters and numbers) of a given length.
66
+ *
67
+ * This function uses cryptographically secure randomness.
68
+ */
69
+ function randomString(inputLength = 16) {
70
+ const arrayLength = Math.ceil(inputLength / 2);
71
+ const uintArray = new Uint8Array(arrayLength);
72
+ crypto.getRandomValues(uintArray);
73
+ return (Array.from(uintArray)
74
+ .map((value) => value.toString(16).padStart(2, '0'))
75
+ .join('')
76
+ /**
77
+ * Because getRandomValues works with even numbers only, we must then chop off extra
78
+ * characters if they exist in the even that inputLength was odd.
79
+ */
80
+ .substring(0, inputLength));
81
+ }
82
+ exports.randomString = randomString;
83
+ /* c8 ignore stop */
package/dist/cjs/index.js CHANGED
@@ -41,6 +41,7 @@ __exportStar(require("./augments/object/old-union-to-intersection"), exports);
41
41
  __exportStar(require("./augments/object/pick-deep"), exports);
42
42
  __exportStar(require("./augments/object/typed-has-property"), exports);
43
43
  __exportStar(require("./augments/promise"), exports);
44
+ __exportStar(require("./augments/random"), exports);
44
45
  __exportStar(require("./augments/regexp"), exports);
45
46
  __exportStar(require("./augments/runtime-type-of"), exports);
46
47
  __exportStar(require("./augments/string/prefixes"), exports);
@@ -0,0 +1,76 @@
1
+ import { clamp, ensureMinAndMax } from './common-number';
2
+ const crypto = globalThis.crypto;
3
+ // can't get this coverage to work
4
+ /* c8 ignore start */
5
+ /**
6
+ * Creates a random integer (decimal points are all cut off) between the given min and max
7
+ * (inclusive).
8
+ *
9
+ * This function uses cryptographically secure randomness.
10
+ */
11
+ export function randomInteger({ min: rawMin, max: rawMax }) {
12
+ const { min, max } = ensureMinAndMax({ min: Math.floor(rawMin), max: Math.floor(rawMax) });
13
+ const range = max - min + 1;
14
+ const neededByteCount = Math.ceil(Math.log2(range) / 8);
15
+ const cutoff = Math.floor(256 ** neededByteCount / range) * range;
16
+ const currentBytes = new Uint8Array(neededByteCount);
17
+ let value;
18
+ do {
19
+ crypto.getRandomValues(currentBytes);
20
+ value = currentBytes.reduce((accum, byte, index) => {
21
+ return accum + byte * 256 ** index;
22
+ }, 0);
23
+ } while (value >= cutoff);
24
+ return min + (value % range);
25
+ }
26
+ /**
27
+ * Returns true at rate of the percentLikelyToBeTrue input. Inputs should be whole numbers which
28
+ * will be treated like percents. Anything outside of 0-100 inclusively will be clamped. An input 0
29
+ * will always return true. An input of 100 will always return true. Decimals on the input will be
30
+ * chopped off, use whole numbers.
31
+ *
32
+ * This function uses cryptographically secure randomness.
33
+ *
34
+ * @example
35
+ * randomBoolean(50); // 50% chance to return true
36
+ *
37
+ * @example
38
+ * randomBoolean(0); // always false, 0% chance of being true
39
+ *
40
+ * @example
41
+ * randomBoolean(100); // always true, 100% chance of being true
42
+ *
43
+ * @example
44
+ * randomBoolean(59.67; // 59% chance of being true
45
+ */
46
+ export function randomBoolean(percentLikelyToBeTrue = 50) {
47
+ return (randomInteger({ min: 0, max: 99 }) <
48
+ clamp({
49
+ value: Math.floor(percentLikelyToBeTrue),
50
+ min: 0,
51
+ max: 100,
52
+ }));
53
+ }
54
+ /** Creates a cryptographically secure uuid. */
55
+ export function createUuid() {
56
+ return crypto.randomUUID();
57
+ }
58
+ /**
59
+ * Creates a random string (including letters and numbers) of a given length.
60
+ *
61
+ * This function uses cryptographically secure randomness.
62
+ */
63
+ export function randomString(inputLength = 16) {
64
+ const arrayLength = Math.ceil(inputLength / 2);
65
+ const uintArray = new Uint8Array(arrayLength);
66
+ crypto.getRandomValues(uintArray);
67
+ return (Array.from(uintArray)
68
+ .map((value) => value.toString(16).padStart(2, '0'))
69
+ .join('')
70
+ /**
71
+ * Because getRandomValues works with even numbers only, we must then chop off extra
72
+ * characters if they exist in the even that inputLength was odd.
73
+ */
74
+ .substring(0, inputLength));
75
+ }
76
+ /* c8 ignore stop */
package/dist/esm/index.js CHANGED
@@ -25,6 +25,7 @@ export * from './augments/object/old-union-to-intersection';
25
25
  export * from './augments/object/pick-deep';
26
26
  export * from './augments/object/typed-has-property';
27
27
  export * from './augments/promise';
28
+ export * from './augments/random';
28
29
  export * from './augments/regexp';
29
30
  export * from './augments/runtime-type-of';
30
31
  export * from './augments/string/prefixes';
@@ -1,7 +1,6 @@
1
- export type BaseObject = Record<PropertyKey, unknown>;
2
1
  /**
3
2
  * Accepts multiple objects and merges their key-value pairs recursively.
4
3
  *
5
4
  * Note that order matters! Each input object will overwrite the properties of the previous objects.
6
5
  */
7
- export declare function mergeDeep<T extends BaseObject>(...inputs: (T | Partial<T>)[]): T;
6
+ export declare function mergeDeep<T extends object>(...inputs: (T | Partial<T>)[]): T;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Creates a random integer (decimal points are all cut off) between the given min and max
3
+ * (inclusive).
4
+ *
5
+ * This function uses cryptographically secure randomness.
6
+ */
7
+ export declare function randomInteger({ min: rawMin, max: rawMax }: {
8
+ min: number;
9
+ max: number;
10
+ }): number;
11
+ /**
12
+ * Returns true at rate of the percentLikelyToBeTrue input. Inputs should be whole numbers which
13
+ * will be treated like percents. Anything outside of 0-100 inclusively will be clamped. An input 0
14
+ * will always return true. An input of 100 will always return true. Decimals on the input will be
15
+ * chopped off, use whole numbers.
16
+ *
17
+ * This function uses cryptographically secure randomness.
18
+ *
19
+ * @example
20
+ * randomBoolean(50); // 50% chance to return true
21
+ *
22
+ * @example
23
+ * randomBoolean(0); // always false, 0% chance of being true
24
+ *
25
+ * @example
26
+ * randomBoolean(100); // always true, 100% chance of being true
27
+ *
28
+ * @example
29
+ * randomBoolean(59.67; // 59% chance of being true
30
+ */
31
+ export declare function randomBoolean(percentLikelyToBeTrue?: number): boolean;
32
+ /** Creates a cryptographically secure uuid. */
33
+ export declare function createUuid(): `${string}-${string}-${string}-${string}-${string}`;
34
+ /**
35
+ * Creates a random string (including letters and numbers) of a given length.
36
+ *
37
+ * This function uses cryptographically secure randomness.
38
+ */
39
+ export declare function randomString(inputLength?: number): string;
@@ -25,6 +25,7 @@ export * from './augments/object/old-union-to-intersection';
25
25
  export * from './augments/object/pick-deep';
26
26
  export * from './augments/object/typed-has-property';
27
27
  export * from './augments/promise';
28
+ export * from './augments/random';
28
29
  export * from './augments/regexp';
29
30
  export * from './augments/runtime-type-of';
30
31
  export * from './augments/string/prefixes';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@augment-vir/common",
3
- "version": "19.6.0",
3
+ "version": "20.0.1",
4
4
  "homepage": "https://github.com/electrovir/augment-vir/tree/main/packages/common",
5
5
  "bugs": {
6
6
  "url": "https://github.com/electrovir/augment-vir/issues"
@@ -24,6 +24,7 @@
24
24
  "test:types": "tsc --noEmit"
25
25
  },
26
26
  "dependencies": {
27
+ "browser-or-node": "^2.1.1",
27
28
  "type-fest": "^4.4.0"
28
29
  },
29
30
  "devDependencies": {