Skip to content

Commit 6bcdaf2

Browse files
committed
Use a small seeded PRNG directly embedded in the code
1 parent 1b8f847 commit 6bcdaf2

File tree

5 files changed

+42
-35
lines changed

5 files changed

+42
-35
lines changed

package-lock.json

Lines changed: 1 addition & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,13 @@
3232
"README.md"
3333
],
3434
"dependencies": {
35-
"luxon": "^3.6.1",
36-
"seedrandom": "^3.0.5"
35+
"luxon": "^3.6.1"
3736
},
3837
"devDependencies": {
3938
"@tsd/typescript": "^5.8.2",
4039
"@types/jest": "^29.5.14",
4140
"@types/luxon": "^3.6.2",
4241
"@types/node": "^22.14.0",
43-
"@types/seedrandom": "^3.0.8",
4442
"@typescript-eslint/eslint-plugin": "^8.29.0",
4543
"@typescript-eslint/parser": "^8.29.0",
4644
"chalk": "^5.4.1",

src/CronExpressionParser.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import seedrandom, { type PRNG } from 'seedrandom';
2-
31
import { CronFieldCollection } from './CronFieldCollection';
42
import { CronDate } from './CronDate';
53
import { CronExpression, CronExpressionOptions } from './CronExpression';
4+
import { type PRNG, seededRandom } from './utils';
65
import {
76
CronSecond,
87
CronMinute,
@@ -96,7 +95,7 @@ export class CronExpressionParser {
9695
const { strict = false } = options;
9796
const currentDate = options.currentDate || new CronDate();
9897

99-
const rand = options.seed ? seedrandom(options.seed) : seedrandom();
98+
const rand = options.seed ? seededRandom(options.seed) : seededRandom();
10099

101100
expression = PredefinedExpressions[expression as keyof typeof PredefinedExpressions] || expression;
102101
const rawFields = CronExpressionParser.#getRawFields(expression, strict);

src/utils.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Randomness related utils
2+
3+
function xfnv1a(str: string) {
4+
let h = 2166136261 >>> 0;
5+
for (let i = 0; i < str.length; i++) {
6+
h ^= str.charCodeAt(i);
7+
h = Math.imul(h, 16777619);
8+
}
9+
return () => h >>> 0;
10+
}
11+
12+
function mulberry32(seed: number) {
13+
return () => {
14+
let t = (seed += 0x6d2b79f5);
15+
t = Math.imul(t ^ (t >>> 15), t | 1);
16+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
17+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
18+
};
19+
}
20+
21+
export type PRNG = () => number;
22+
export function seededRandom(str?: string): PRNG {
23+
const seed = str ? xfnv1a(str)() : Math.floor(Math.random() * 10_000_000_000);
24+
return mulberry32(seed);
25+
}

tests/CronExpressionParser.test.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,20 +1742,20 @@ describe('CronExpressionParser', () => {
17421742
};
17431743

17441744
const expressions = [
1745-
{ expression: 'H * * * * *', expected: '10 * * * * *' },
1746-
{ expression: '* H * * * *', expected: '* 33 * * * *' },
1747-
{ expression: '* * H * * *', expected: '* * 19 * * *' },
1748-
{ expression: '* * * H * *', expected: '* * * 27 * *' },
1745+
{ expression: 'H * * * * *', expected: '5 * * * * *' },
1746+
{ expression: '* H * * * *', expected: '* 34 * * * *' },
1747+
{ expression: '* * H * * *', expected: '* * 15 * * *' },
1748+
{ expression: '* * * H * *', expected: '* * * 12 * *' },
17491749
{ expression: '* * * * H *', expected: '* * * * 8 *' },
1750-
{ expression: '* * * * * H', expected: '* * * * * 1' },
1751-
{ expression: 'H H * * * *', expected: '10 33 * * * *' },
1752-
{ expression: '* H H * * *', expected: '* 33 19 * * *' },
1753-
{ expression: '* * H H * *', expected: '* * 19 27 * *' },
1754-
{ expression: '* * * H H *', expected: '* * * 27 8 *' },
1755-
{ expression: '* * * * H H', expected: '* * * * 8 1' },
1756-
{ expression: 'H H H H H H', expected: '10 33 19 27 8 1' },
1757-
{ expression: 'H/5 * * * * *', expected: '10/5 * * * * *' },
1758-
{ expression: '* * * * * H#1', expected: '* * * * * 1' },
1750+
{ expression: '* * * * * H', expected: '* * * * * 0' },
1751+
{ expression: 'H H * * * *', expected: '5 34 * * * *' },
1752+
{ expression: '* H H * * *', expected: '* 34 15 * * *' },
1753+
{ expression: '* * H H * *', expected: '* * 15 12 * *' },
1754+
{ expression: '* * * H H *', expected: '* * * 12 8 *' },
1755+
{ expression: '* * * * H H', expected: '* * * * 8 0' },
1756+
{ expression: 'H H H H H H', expected: '5 34 15 12 8 0' },
1757+
{ expression: 'H/5 * * * * *', expected: '5/5 * * * * *' },
1758+
{ expression: '* * * * * H#1', expected: '* * * * * 0' },
17591759
];
17601760

17611761
for (const { expression, expected } of expressions) {

0 commit comments

Comments
 (0)