@williamthorsen/toolbelt.numbers 7.0.3 → 7.1.0

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.
@@ -1,6 +1,6 @@
1
1
  /** @noformat -- @generated. Do not edit. Compiled by rdy. */
2
2
  /* eslint-disable */
3
- export const __readyupVersion = "0.34.0";
3
+ export const __readyupVersion = "0.35.0";
4
4
 
5
5
 
6
6
  // ../adoption/src/conventions/path-predicates.ts
@@ -50,7 +50,7 @@ import {
50
50
  countPackageUsage,
51
51
  readTrackedSources
52
52
  } from "readyup/check-utils";
53
- var NOT_A_REPO = "the project is not a git working tree, and these checks read the files git tracks";
53
+ var NOT_A_REPO = "the project is not a git working tree, and these checks read the files that git tracks";
54
54
  var NOTHING_TO_REPORT = { findings: [] };
55
55
  function defineAdoptionKit(spec) {
56
56
  assertCheckIdsAreUnique();
@@ -273,8 +273,8 @@ var default_default = defineAdoptionKit({
273
273
  exportNames: ADOPTED_EXPORTS,
274
274
  noSourcesReason: "the project holds no JavaScript or TypeScript sources outside the exempt paths",
275
275
  packageName: PACKAGE_NAME,
276
- // A test computes these values deliberately, and a bootstrap wrapper's hand-rolled arithmetic is what keeps
277
- // its build-first message alive through an incomplete install.
276
+ // A test computes these values deliberately, and a bootstrap wrapper's hand-rolled arithmetic keeps its
277
+ // build-first message alive through an incomplete install.
278
278
  pathFilter: isAdoptableSource,
279
279
  checks: [
280
280
  {
@@ -289,7 +289,7 @@ var default_default = defineAdoptionKit({
289
289
  id: "no-hand-rolled-round",
290
290
  kinds: ["round-scale"],
291
291
  severity: "recommend",
292
- fix: `Replace each expression named above with round from ${PACKAGE_NAME}/candidate, called as round(value, places). The substitution is exact: round scales by the same power of ten these sites write out. Reference: ${README_URL}`
292
+ fix: `Replace each expression named above with round from ${PACKAGE_NAME}/candidate, called as round(value, places). The substitution is exact: round scales by the same power of ten that these sites write out. Reference: ${README_URL}`
293
293
  },
294
294
  {
295
295
  name: "No source derives a random integer by hand",
@@ -9,37 +9,37 @@
9
9
  "esbuildVersion": "0.28.2",
10
10
  "inputs": [
11
11
  {
12
- "hash": "9cbd3541",
12
+ "hash": "b9007d48",
13
13
  "kind": "module",
14
14
  "path": "../../adoption/src/conventions/path-predicates.ts"
15
15
  },
16
16
  {
17
- "hash": "c7d90b66",
17
+ "hash": "84c99907",
18
18
  "kind": "module",
19
19
  "path": "../../adoption/src/conventions/site-handoffs.ts"
20
20
  },
21
21
  {
22
- "hash": "3a124dad",
22
+ "hash": "3372fb44",
23
23
  "kind": "module",
24
24
  "path": "../../adoption/src/kits/defineAdoptionKit.ts"
25
25
  },
26
26
  {
27
- "hash": "6e5a8dda",
27
+ "hash": "dee2a3a3",
28
28
  "kind": "module",
29
29
  "path": "../../adoption/src/mod.ts"
30
30
  },
31
31
  {
32
- "hash": "e8d0444d",
32
+ "hash": "6fdaacac",
33
33
  "kind": "module",
34
34
  "path": "../../adoption/src/portable/condenseWhitespace.ts"
35
35
  },
36
36
  {
37
- "hash": "b6d99ce7",
37
+ "hash": "15a78157",
38
38
  "kind": "module",
39
39
  "path": "../../adoption/src/portable/listFunctionBodies.ts"
40
40
  },
41
41
  {
42
- "hash": "4d2d8e11",
42
+ "hash": "1d2261fb",
43
43
  "kind": "module",
44
44
  "path": "../../adoption/src/portable/readAnchoredWindow.ts"
45
45
  },
@@ -49,42 +49,47 @@
49
49
  "path": "../../adoption/src/portable/readBalancedGroup.ts"
50
50
  },
51
51
  {
52
- "hash": "e6df5682",
52
+ "hash": "e9427d50",
53
+ "kind": "module",
54
+ "path": "../../adoption/src/portable/readLiteral.ts"
55
+ },
56
+ {
57
+ "hash": "24f6e6db",
53
58
  "kind": "module",
54
59
  "path": "kits/default.ts"
55
60
  },
56
61
  {
57
- "hash": "f3d9105b",
62
+ "hash": "05bd292b",
58
63
  "kind": "module",
59
64
  "path": "../src/readiness/adoptedExports.ts"
60
65
  },
61
66
  {
62
- "hash": "54ee66e5",
67
+ "hash": "f14085f3",
63
68
  "kind": "module",
64
69
  "path": "../src/readiness/listClampNestLines.ts"
65
70
  },
66
71
  {
67
- "hash": "47d35285",
72
+ "hash": "eabb769f",
68
73
  "kind": "module",
69
74
  "path": "../src/readiness/listMathIdioms.ts"
70
75
  },
71
76
  {
72
- "hash": "fa0a23b7",
77
+ "hash": "827c07b2",
73
78
  "kind": "module",
74
79
  "path": "../src/readiness/listRandomIntegerLines.ts"
75
80
  },
76
81
  {
77
- "hash": "ae0ac903",
82
+ "hash": "bdcac255",
78
83
  "kind": "module",
79
84
  "path": "../src/readiness/listRoundScaleLines.ts"
80
85
  }
81
86
  ],
82
87
  "name": "default",
83
88
  "path": "kits/default.js",
84
- "readyupVersion": "0.34.0",
89
+ "readyupVersion": "0.35.0",
85
90
  "source": "kits/default.ts",
86
- "sourceHash": "e6df5682",
87
- "targetHash": "44b320aa"
91
+ "sourceHash": "24f6e6db",
92
+ "targetHash": "cee2ac4e"
88
93
  }
89
94
  ]
90
95
  }
package/CHANGELOG.md CHANGED
@@ -2,6 +2,49 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## 7.1.0 — 2026-09-06
6
+
7
+ ### Features
8
+
9
+ - Add a ReadyUp adoption kit (#253)
10
+
11
+ Adds a ReadyUp adoption kit to `@williamthorsen/toolbelt.objects`. The kit recommends `Object.hasOwn` or the package's own `hasOwnProperty` in place of a call reached through `Object.prototype`, and `isRecord` or `isRecordOrArray` in place of a guard written as `typeof value === 'object' && value !== null`. Its third check warns that a comparison of two `JSON.stringify` calls is key-order dependent and should be replaced by `isEqual`.
12
+
13
+ - Add a ReadyUp adoption kit reporting hand-rolled sleeps (#303)
14
+
15
+ - Adds a ReadyUp adoption kit to `@williamthorsen/toolbelt.async` that recommends the use of `delay` to replace a hand-rolled sleep.
16
+
17
+ ### Dependencies
18
+
19
+ - Upgrade all deps to latest version
20
+ - Upgrade all deps to latest version
21
+
22
+ ### Documentation
23
+
24
+ - Document the generated-source exemption in the adoption kits (#251)
25
+
26
+ Documents the generated- and vendored-source exemption in the `errors`, `numbers`, and `strings` READMEs.
27
+
28
+ - Repair reduced object relatives in passages recurring across files (#262)
29
+
30
+ Repairs the reduced object relative in the prose passages that recur across more than one file, in package READMEs, source comments, test titles, and the ReadyUp kits' check messages.
31
+
32
+ - Repair reduced object relatives in the READMEs and AGENTS.md (#263)
33
+
34
+ Repairs the reduced object relative in `AGENTS.md`, the root `README.md`, and the package READMEs.
35
+
36
+ - Repair reduced object relatives in packages/adoption (#264)
37
+
38
+ Repairs the reduced object relative in `packages/adoption`, in source comments, doc descriptions, and test titles.
39
+
40
+ - Repair reduced object relatives in the readiness modules and kits (#265)
41
+
42
+ Repairs the reduced object relative in the six kit-bearing packages' readiness modules and ReadyUp kit sources, across comments, doc descriptions, test titles, and the kits' check messages.
43
+
44
+ - Repair the repository's prose and record every rejection's ground (#290)
45
+
46
+ Applies one repo-wide `revise-prose` sweep across the repository's READMEs, `AGENTS.md`, source comments, doc descriptions, and test names.
47
+
5
48
  ## 7.0.3 — 2026-08-30
6
49
 
7
50
  ### Bug fixes
package/README.md CHANGED
@@ -3,13 +3,17 @@
3
3
  Utility functions for working with numbers.
4
4
 
5
5
  <!-- section:release-notes -->
6
- ## Release notes — v7.0.3 (2026-08-30)
6
+ ## Release notes — v7.1.0 (2026-09-06)
7
7
 
8
- ### Bug fixes
8
+ ### Features
9
9
 
10
- - Reject a check declaring a kind its detector never produces (#246)
10
+ - Add a ReadyUp adoption kit (#253)
11
11
 
12
- Fixes an issue where an adoption check could declare a kind its kit's detector never produces. `Kind` was inferred from `checks` and `detect` together, so a typo in a check's `kinds` widened `Kind` rather than failing.
12
+ Adds a ReadyUp adoption kit to `@williamthorsen/toolbelt.objects`. The kit recommends `Object.hasOwn` or the package's own `hasOwnProperty` in place of a call reached through `Object.prototype`, and `isRecord` or `isRecordOrArray` in place of a guard written as `typeof value === 'object' && value !== null`. Its third check warns that a comparison of two `JSON.stringify` calls is key-order dependent and should be replaced by `isEqual`.
13
+
14
+ - Add a ReadyUp adoption kit reporting hand-rolled sleeps (#303)
15
+
16
+ - Adds a ReadyUp adoption kit to `@williamthorsen/toolbelt.async` that recommends the use of `delay` to replace a hand-rolled sleep.
13
17
  <!-- /section:release-notes -->
14
18
 
15
19
  ## Installation
@@ -28,7 +32,7 @@ Requires Node.js 24 or later.
28
32
  clamp(value: number, bounds: { min?: number; max?: number }): number;
29
33
  ```
30
34
 
31
- Returns the value constrained to the inclusive bounds; an omitted bound leaves that side unconstrained. A reversed range or a `NaN` bound throws a `RangeError`, where the `Math.max(min, Math.min(max, value))` idiom it replaces returns a value for both. A `NaN` value passes through.
35
+ Returns the value constrained to the inclusive bounds; an omitted bound leaves that side unconstrained. A reversed range or a `NaN` bound throws a `RangeError`, where the `Math.max(min, Math.min(max, value))` idiom that it replaces returns a value for both. A `NaN` value passes through.
32
36
 
33
37
  ```ts
34
38
  import { clamp } from '@williamthorsen/toolbelt.numbers/candidate';
@@ -57,9 +61,9 @@ round(3.14159, 2); // 3.14
57
61
  pickInteger(params?: { min?: number; max?: number; seed?: Seed }): number;
58
62
  ```
59
63
 
60
- Returns a random integer between the bounds, **inclusive** of both, and truncates a non-integer bound. Passing a seed makes the draw deterministic, which is what a test wants.
64
+ Returns a random integer between the bounds, **inclusive** of both, and truncates a non-integer bound. Passing a seed makes the draw deterministic, which a test wants.
61
65
 
62
- Mind the bound when replacing `Math.floor(Math.random() * n)`: that idiom stops at `n - 1`, so the equivalent is `pickInteger({ max: n - 1 })`.
66
+ Mind the bound when replacing `Math.floor(Math.random() * n)`: That idiom stops at `n - 1`, so the equivalent is `pickInteger({ max: n - 1 })`.
63
67
 
64
68
  ```ts
65
69
  import { pickInteger } from '@williamthorsen/toolbelt.numbers/candidate';
@@ -75,11 +79,11 @@ The package ships a ReadyUp kit, so a project that installs it can ask how far i
75
79
  rdy run --packages
76
80
  ```
77
81
 
78
- The kit reads the project's tracked sources and reports every hand-rolled clamp, decimal rounding, and random integer in them, each counted against the calls the project already makes into this package. All three report at `recommend`: they are correct code that a published utility expresses better, not defects.
82
+ The kit reads the project's tracked sources and reports every hand-rolled clamp, decimal rounding, and random integer in them, each counted against the calls that the project already makes into this package. All three report at `recommend`: They are correct code that a published utility expresses better, not defects.
79
83
 
80
84
  A random integer used as an array subscript is left alone. That site belongs to `@williamthorsen/toolbelt.arrays`, whose `pickItem` covers it, and reporting it here would mean seeing one line twice under conflicting advice.
81
85
 
82
- Bootstrap wrappers under `bin/` are exempt: such a wrapper imports only builtins so its build-first message survives an incomplete install, and importing this package there would replace that message with a module-resolution failure. Tests are exempt too, since they compute these values deliberately.
86
+ Bootstrap wrappers under `bin/` are exempt: Such a wrapper imports only builtins so its build-first message survives an incomplete install, and importing this package there would replace that message with a module-resolution failure. Tests are exempt too, since they compute these values deliberately. A source declared generated or vendored by the project in its own `.gitattributes`, under `linguist-generated` or `linguist-vendored`, is exempt as well: The sweep drops it before the kit sees it, so committed bundler output yields no advice that anyone could act on. The sweep is readyup's, so this holds on readyup 0.35.0 or later.
83
87
 
84
88
  A reviewed site is silenced by an `rdy-ignore` pragma on its own line, or `rdy-ignore-next-line` on the line above. A pragma naming a check's id suppresses that check alone; with no id it covers every check on the line. A failed check prints its id ahead of its fraction, which is the form to write:
85
89
 
@@ -1,2 +1,7 @@
1
- import type { Seed } from '../internal/evaluateSeed.js';
1
+ import { type Seed } from '../internal/evaluateSeed.js';
2
+ /**
3
+ * Returns a number generator whose output, when invoked successively, is a pseudo-random
4
+ * series of numbers that deterministically depend on the initial seed (or pseudo-random if no seed is given).
5
+ * This is not intended to be a cryptographically secure random number generator.
6
+ */
2
7
  export declare function makeRng(seed?: Seed): () => number;
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Returns the value constrained to the inclusive bounds; an omitted bound leaves that side unconstrained.
3
+ * A NaN value passes through, but a NaN bound or a min greater than max throws a RangeError.
4
+ *
5
+ * @category Number
6
+ * @experimental
7
+ * @stage candidate
8
+ */
1
9
  export declare function clamp(value: number, bounds: ClampBounds): number;
2
10
  export interface ClampBounds {
3
11
  readonly max?: number | undefined;
@@ -1,4 +1,7 @@
1
- import type { Seed } from '../internal/evaluateSeed.js';
1
+ import { type Seed } from '../internal/evaluateSeed.js';
2
+ /**
3
+ * Returns a scaled random number in the range [min, max).
4
+ */
2
5
  export declare function generateRandom(options?: Options): number;
3
6
  interface Options {
4
7
  max?: number | undefined;
@@ -1,4 +1,23 @@
1
1
  import type { Maybe } from '../internal/internal.types.js';
2
+ /**
3
+ * Returns true if the value is a string that represents a valid integer.
4
+ *
5
+ * @category Type Guards
6
+ * @experimental
7
+ * @stage candidate
8
+ */
2
9
  export declare function isIntegerString(value: string | null | undefined): value is string;
10
+ /**
11
+ * Attempts to parse an integer from a string and returns the parsed integer.
12
+ * If the input does not represent a valid integer, returns the fallback value or throws the fallback error.
13
+ *
14
+ * @param value - The string to parse.
15
+ * @param fallback - The value to return if parsing fails.
16
+ * @returns The parsed integer or the fallback value.
17
+ *
18
+ * @category Type Guards
19
+ * @experimental
20
+ * @stage candidate
21
+ */
3
22
  export declare function safeParseInteger(value: Maybe<string>, fallback: number | Error): number;
4
23
  export declare function safeParseInteger(value: Maybe<string>, fallback?: undefined): number | undefined;
@@ -1,4 +1,25 @@
1
1
  import type { Maybe } from '../internal/internal.types.js';
2
+ /**
3
+ * Returns true if the value is a string that represents a valid finite number.
4
+ *
5
+ * Accepts integers, decimals, and scientific notation (e.g., "1e3").
6
+ *
7
+ * @category Type Guards
8
+ * @experimental
9
+ * @stage candidate
10
+ */
2
11
  export declare function isNumericString(value: string | null | undefined): value is string;
12
+ /**
13
+ * Attempts to parse a number from a string and returns the parsed number.
14
+ * If the input does not represent a valid number, returns the fallback value or throws the fallback error.
15
+ *
16
+ * @param value - The string to parse.
17
+ * @param fallback - The value to return if parsing fails.
18
+ * @returns The parsed number or the fallback value.
19
+ *
20
+ * @category Type Guards
21
+ * @experimental
22
+ * @stage candidate
23
+ */
3
24
  export declare function safeParseNumber(value: Maybe<string>, fallback: number | Error): number;
4
25
  export declare function safeParseNumber(value: Maybe<string>, fallback?: undefined): number | undefined;
@@ -1,4 +1,8 @@
1
1
  import type { Seed } from '../internal/evaluateSeed.js';
2
+ /**
3
+ * Returns a random integer between the bounds inclusive.
4
+ * If the bounds are not integers, they are truncated to integers.
5
+ */
2
6
  export declare function pickInteger(params?: Params): number;
3
7
  interface Params {
4
8
  max?: number | undefined;
@@ -1 +1,6 @@
1
+ /**
2
+ * Returns the number rounded to the given number of decimal places, or 0 if no nDecimalPlaces is specified.
3
+ * @param value
4
+ * @param nDecimalPlaces
5
+ */
1
6
  export declare function round(value: number, nDecimalPlaces?: number): number;
@@ -1,9 +1,15 @@
1
+ /**
2
+ * Scales a number from one range to another.
3
+ */
1
4
  export declare function scale(value: number, toRange: Range, fromRange?: Partial<Range>): number;
2
5
  export declare function scaleInt(value: number, toRange: Range, fromRange?: Partial<IntegerRange>): number;
3
6
  interface Range {
4
7
  min: number;
5
8
  max: number;
6
9
  }
10
+ /**
11
+ * Represents a range of integers. Non-integer values should be truncated by the called function.
12
+ */
7
13
  interface IntegerRange {
8
14
  min: number;
9
15
  max: number;
@@ -1,24 +1,46 @@
1
- import type { Seed, SeededGenerator } from '../internal/evaluateSeed.js';
1
+ import { type Seed, type SeededGenerator } from '../internal/evaluateSeed.js';
2
+ /**
3
+ * Class that manages a pseudo-random number generator that behaves deterministically when given a seed.
4
+ */
2
5
  export declare class SeededRng implements SeededGenerator {
3
6
  private _seed;
4
7
  private baseSeed;
5
8
  private nIncrements;
9
+ /**
10
+ * Constructor
11
+ */
6
12
  constructor(seed?: Seed);
7
13
  get maxBase(): number;
8
14
  get rng(): () => number;
9
15
  get seed(): number;
10
16
  static evaluateSeed(seed?: Seed): number | undefined;
17
+ /**
18
+ * Creates a child from a seed without mutating the parent seed.
19
+ */
11
20
  static clone<T extends ThisConstructor<typeof SeededRng>>(this: T, seed: undefined, nIncrements?: number): undefined;
12
21
  static clone<T extends ThisConstructor<typeof SeededRng>>(this: T, seed: Seed, nIncrements?: number): This<T>;
13
22
  static clone<T extends ThisConstructor<typeof SeededRng>>(this: T, seed: Seed | undefined, nIncrements?: number): This<T> | undefined;
23
+ /**
24
+ * Clones the given seed or creates a new one if none is given.
25
+ */
14
26
  static cloneOrCreate<T extends ThisConstructor<typeof SeededRng>>(this: T, seed?: Seed, nIncrements?: number): This<T>;
15
27
  static spawn<T extends ThisConstructor<typeof SeededRng>>(this: T, seed: undefined): undefined;
16
28
  static spawn<T extends ThisConstructor<typeof SeededRng>>(this: T, seed: Seed): This<T>;
17
29
  static spawn<T extends ThisConstructor<typeof SeededRng>>(this: T, seed: Seed | undefined): This<T> | undefined;
30
+ /**
31
+ * Given a seed-accepting function and an optional seed, returns a new function that passes the seed to the function.
32
+ * The spawned generator is an instance of the class on which the method is called, so subclasses supply their
33
+ * own sequence.
34
+ */
18
35
  static withSeed<TOptions extends object, R>(fn: (options?: OptionsWithSeed<TOptions> | OptionsWithSeed<EmptyObject>) => R, seed: Seed | undefined): (options?: TOptions) => R;
19
36
  clone<T extends SeededRng>(this: T, nIncrements?: number): T;
37
+ /** Safely increments the seed by the given number of increments */
20
38
  increment(nIncrements?: number): this;
21
39
  next(n?: number): number;
40
+ /**
41
+ * Returns the next value in the pseudo-random sequence without incrementing the seed.
42
+ * For use in testing and debugging.
43
+ */
22
44
  peek(): number;
23
45
  scaleDownSeed(seed: number): number;
24
46
  scaleUpSeed(value: number): number;
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Wrapper for `toIntegerSeed` that provides static properties for generating new seeds.
3
+ *
4
+ * @internal
5
+ */
1
6
  export declare const IntegerSeed: {
2
7
  max: number;
3
8
  multiplier: number;
@@ -1 +1,6 @@
1
+ /**
2
+ * Deterministically computes and returns a number in the range [0, 1) based on the input.
3
+ *
4
+ * @internal
5
+ */
1
6
  export declare function computeFakeMathRandom(seed: number): number;
@@ -1,5 +1,18 @@
1
+ /**
2
+ * Resolves a seed to its numeric value, returning `undefined` when there is no seed.
3
+ *
4
+ * @internal
5
+ */
1
6
  export declare function evaluateSeed(seed: Seed | undefined): number | undefined;
7
+ /**
8
+ * Narrows a seed to a generator.
9
+ *
10
+ * @internal
11
+ */
2
12
  export declare function checkIsRngLike(seed: Seed | undefined): seed is SeededGenerator;
13
+ /**
14
+ * Interface describing an object that returns a sequence of numbers.
15
+ */
3
16
  export interface SeededGenerator {
4
17
  seed: number;
5
18
  next(): number;
@@ -1 +1,6 @@
1
+ /**
2
+ * Returns the sum of the given addends, wrapping around from 0 when the given max is exceeded.
3
+ *
4
+ * @internal
5
+ */
1
6
  export declare function wrapSum(max: number, ...addends: number[]): number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@williamthorsen/toolbelt.numbers",
3
- "version": "7.0.3",
3
+ "version": "7.1.0",
4
4
  "description": "Utility functions for working with numbers",
5
5
  "keywords": [
6
6
  "esm",
@@ -46,10 +46,10 @@
46
46
  "CHANGELOG.md"
47
47
  ],
48
48
  "devDependencies": {
49
- "esbuild": "0.28.2",
50
- "readyup": "0.34.0",
51
49
  "@williamthorsen/toolbelt.adoption": "0.1.0",
52
- "@williamthorsen/toolbelt.testing": "0.5.0"
50
+ "@williamthorsen/toolbelt.testing": "0.5.1",
51
+ "esbuild": "0.28.2",
52
+ "readyup": "0.35.0"
53
53
  },
54
54
  "engines": {
55
55
  "node": ">=24.0.0"