From 08cfd0b85db284edd5be4d0e88f0579884a0d0b9 Mon Sep 17 00:00:00 2001 From: Maghuro <1546139+maghuro@users.noreply.github.com> Date: Fri, 2 Oct 2026 13:49:27 +0100 Subject: [PATCH 1/5] Fix chat number formatting across giveaway lists --- userscripts/giveaway/src/12-utilities.js | 31 ++++++++++++++++++------ 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/userscripts/giveaway/src/12-utilities.js b/userscripts/giveaway/src/12-utilities.js index ae79a7fe..85bb3d6c 100644 --- a/userscripts/giveaway/src/12-utilities.js +++ b/userscripts/giveaway/src/12-utilities.js @@ -1453,8 +1453,23 @@ if (!str) return str; const raw = String(str); - // Quick bailout: nothing that looks like a 4+ digit number or grouped digits. - if (!/\d{4}/.test(raw) && !/\d{1,3}[,\s'’]\d{3}/.test(raw)) return raw; + + // Only treat one lexical numeric token at a time as a thousands-formatted + // number. In particular, comma+space is intentionally NOT a thousands + // separator because giveaway lists use it between independent values: + // "28, 36, 52, 83, 89" must never become "28, 365 283, 89". + // + // Supported forms: + // 1000 / 1000000 + // 1,000 / 1,000,000 + // 1 000 / 1 000 000 (including NBSP/narrow NBSP) + // 1'000 / 1’000’000 + const formattableNumberRe = + /\b(?:\d{4,}|\d{1,3}(?:,\d{3})+|\d{1,3}(?:[ \u00A0\u202F]\d{3})+|\d{1,3}(?:['’]\d{3})+)\b/; + + // Quick bailout also avoids usernames such as "Sch2021" waking the + // formatter up merely because they contain four consecutive digits. + if (!formattableNumberRe.test(raw)) return raw; // Protect URL segments and BBCode tags/attributes from numeric formatting. // This keeps [tag=...], [url=...], and color hexes untouched. @@ -1464,11 +1479,13 @@ return `__BG_PROTECTED_${idx}__`; }); - const formatted = protectedText.replace(/\b\d[\d,\s'’]*\d\b/g, (match) => { - const digits = match.replace(/[^\d]/g, ""); - if (digits.length < 4) return match; - return digits.replace(/\B(?=(\d{3})+(?!\d))/g, " "); - }); + const formatted = protectedText.replace( + /\b(?:\d{4,}|\d{1,3}(?:,\d{3})+|\d{1,3}(?:[ \u00A0\u202F]\d{3})+|\d{1,3}(?:['’]\d{3})+)\b/g, + (match) => { + const digits = match.replace(/[^\d]/g, ""); + return digits.replace(/\B(?=(\d{3})+(?!\d))/g, " "); + } + ); return formatted.replace(/__BG_PROTECTED_(\d+)__/g, (_, i) => protectedParts[Number(i)] ?? ""); } catch { From 8180aec38348d544212cf786c5d1d208eb8ce17b Mon Sep 17 00:00:00 2001 From: Maghuro <1546139+maghuro@users.noreply.github.com> Date: Fri, 2 Oct 2026 13:49:41 +0100 Subject: [PATCH 2/5] Bump BONanza to 1.5.13 --- userscripts/giveaway/src/00-preamble.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/userscripts/giveaway/src/00-preamble.js b/userscripts/giveaway/src/00-preamble.js index 7a887730..676d578d 100644 --- a/userscripts/giveaway/src/00-preamble.js +++ b/userscripts/giveaway/src/00-preamble.js @@ -2,7 +2,7 @@ // @name DarkPeers BONanza Giveaway | Maghuro Fork // @namespace https://darkpeers.org/users/maghuro // @description BON giveaways on DarkPeers with an optional direct contribution to the BON Pool -// @version 1.5.12 +// @version 1.5.13 // @author 🤖 T.R.A.V.I.S., Maghuro & M.A.E.S.T.R.O. // @homepageURL https://darkpeers.org/users/maghuro // @updateURL https://gist.githubusercontent.com/maghuro/da2dbfec94951990cbc54e75a9aee318/raw/DarkPeers_BONanza_Giveaway.meta.js @@ -236,6 +236,10 @@ // per-notification CSRF-protected PATCH forms, never mass-marks unrelated // notifications, and runs fire-and-forget so cleanup failure cannot block or // roll back giveaway settlement. +// - v1.5.13 fixes chat number formatting so comma-separated giveaway values are +// never collapsed into a fake thousands-grouped number. Usernames containing +// digits (for example Sch2021) no longer trigger unrelated formatting, while +// genuine 1,000 / 1 000 / 1'000-style amounts remain normalized with spaces. //// DarkPeers BONanza fork created and maintained by T.R.A.V.I.S. for the DarkPeers staff. // Further development and maintenance by Maghuro & M.A.E.S.T.R.O. From 0e43ff0b6d4bb0941f811b45bd59919610e763fb Mon Sep 17 00:00:00 2001 From: Maghuro <1546139+maghuro@users.noreply.github.com> Date: Fri, 2 Oct 2026 13:50:04 +0100 Subject: [PATCH 3/5] Add regression tests for giveaway number-list formatting --- tests/bonanza-pure-core.test.mjs | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/bonanza-pure-core.test.mjs b/tests/bonanza-pure-core.test.mjs index e1703039..da812146 100644 --- a/tests/bonanza-pure-core.test.mjs +++ b/tests/bonanza-pure-core.test.mjs @@ -124,6 +124,46 @@ const constantsSource = readSource("userscripts/giveaway/src/01-global-constants const sponsorSource = readSource("userscripts/giveaway/src/09-sponsorship-polling.js"); const payoutSource = readSource("userscripts/giveaway/src/11-winner-selection-payouts.js"); +function loadChatNumberFormatter() { + const context = makeContext(); + const formatter = extractBraceBlock(utilitiesSource, "function formatChatNumbersWithSpaces"); + + vm.runInContext( + `${formatter}\nglobalThis.formatChatNumbersWithSpaces = formatChatNumbersWithSpaces;`, + context + ); + + return context.formatChatNumbersWithSpaces; +} + +test("chat number formatter preserves comma-separated giveaway suggestions with digit-bearing usernames", () => { + const format = loadChatNumberFormatter(); + const message = + "🚫 Sorry d\u200Bemonkadar, but S\u200Bch2021 already entered with number " + + "[color=#DC3D1D][b]61[/b][/color]! Here are some free numbers you can try: " + + "[b][color=#1DDC5D]28, 36, 52, 83, 89[/color][/b]."; + + assert.equal(format(message), message); +}); + +test("chat number formatter never mistakes comma-space list syntax for thousands grouping", () => { + const format = loadChatNumberFormatter(); + + assert.equal( + format("Free numbers: 28, 365, 52, 83, 89."), + "Free numbers: 28, 365, 52, 83, 89." + ); +}); + +test("chat number formatter still normalizes genuine thousands-grouped amounts", () => { + const format = loadChatNumberFormatter(); + + assert.equal( + format("Amounts: 1000 | 1000000 | 1,000,000 | 1 000 000 | 1'000'000 | 1’000’000"), + "Amounts: 1 000 | 1 000 000 | 1 000 000 | 1 000 000 | 1 000 000 | 1 000 000" + ); +}); + function loadFinancialFunctions() { const context = makeContext({ BONANZA: { From bfae7aa4dc937b6453d0b744dc96ebbff32ddb18 Mon Sep 17 00:00:00 2001 From: Maghuro <1546139+maghuro@users.noreply.github.com> Date: Fri, 2 Oct 2026 13:50:11 +0100 Subject: [PATCH 4/5] Update BONanza version regression assertion --- tests/bonanza-review-hardening.test.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bonanza-review-hardening.test.mjs b/tests/bonanza-review-hardening.test.mjs index 59a88425..b03e731c 100644 --- a/tests/bonanza-review-hardening.test.mjs +++ b/tests/bonanza-review-hardening.test.mjs @@ -9,7 +9,7 @@ const sourcePath = new URL( const source = readFileSync(sourcePath, "utf8"); test("review hardening invariants stay present", () => { - assert.match(source, /^\/\/ @version\s+1\.5\.12$/m); + assert.match(source, /^\/\/ @version\s+1\.5\.13$/m); assert.doesNotMatch(source, /pollChatFallback/); assert.doesNotMatch(source, /onlyguardians/i); assert.match(source, /async function getLatestMainChatReplayBoundary\(\)/); From fcd3ba99a745d2f65165e42020c4eb1abcb4da6a Mon Sep 17 00:00:00 2001 From: Maghuro <1546139+maghuro@users.noreply.github.com> Date: Fri, 2 Oct 2026 13:50:25 +0100 Subject: [PATCH 5/5] Rebuild BONanza userscript --- .../DarkPeers_BONanza_Giveaway.user.js | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/userscripts/giveaway/DarkPeers_BONanza_Giveaway.user.js b/userscripts/giveaway/DarkPeers_BONanza_Giveaway.user.js index 5d378b75..d25801ac 100644 --- a/userscripts/giveaway/DarkPeers_BONanza_Giveaway.user.js +++ b/userscripts/giveaway/DarkPeers_BONanza_Giveaway.user.js @@ -2,7 +2,7 @@ // @name DarkPeers BONanza Giveaway | Maghuro Fork // @namespace https://darkpeers.org/users/maghuro // @description BON giveaways on DarkPeers with an optional direct contribution to the BON Pool -// @version 1.5.12 +// @version 1.5.13 // @author 🤖 T.R.A.V.I.S., Maghuro & M.A.E.S.T.R.O. // @homepageURL https://darkpeers.org/users/maghuro // @updateURL https://gist.githubusercontent.com/maghuro/da2dbfec94951990cbc54e75a9aee318/raw/DarkPeers_BONanza_Giveaway.meta.js @@ -236,6 +236,10 @@ // per-notification CSRF-protected PATCH forms, never mass-marks unrelated // notifications, and runs fire-and-forget so cleanup failure cannot block or // roll back giveaway settlement. +// - v1.5.13 fixes chat number formatting so comma-separated giveaway values are +// never collapsed into a fake thousands-grouped number. Usernames containing +// digits (for example Sch2021) no longer trigger unrelated formatting, while +// genuine 1,000 / 1 000 / 1'000-style amounts remain normalized with spaces. //// DarkPeers BONanza fork created and maintained by T.R.A.V.I.S. for the DarkPeers staff. // Further development and maintenance by Maghuro & M.A.E.S.T.R.O. @@ -11873,8 +11877,23 @@ body.host-panel-dragging * { if (!str) return str; const raw = String(str); - // Quick bailout: nothing that looks like a 4+ digit number or grouped digits. - if (!/\d{4}/.test(raw) && !/\d{1,3}[,\s'’]\d{3}/.test(raw)) return raw; + + // Only treat one lexical numeric token at a time as a thousands-formatted + // number. In particular, comma+space is intentionally NOT a thousands + // separator because giveaway lists use it between independent values: + // "28, 36, 52, 83, 89" must never become "28, 365 283, 89". + // + // Supported forms: + // 1000 / 1000000 + // 1,000 / 1,000,000 + // 1 000 / 1 000 000 (including NBSP/narrow NBSP) + // 1'000 / 1’000’000 + const formattableNumberRe = + /\b(?:\d{4,}|\d{1,3}(?:,\d{3})+|\d{1,3}(?:[ \u00A0\u202F]\d{3})+|\d{1,3}(?:['’]\d{3})+)\b/; + + // Quick bailout also avoids usernames such as "Sch2021" waking the + // formatter up merely because they contain four consecutive digits. + if (!formattableNumberRe.test(raw)) return raw; // Protect URL segments and BBCode tags/attributes from numeric formatting. // This keeps [tag=...], [url=...], and color hexes untouched. @@ -11884,11 +11903,13 @@ body.host-panel-dragging * { return `__BG_PROTECTED_${idx}__`; }); - const formatted = protectedText.replace(/\b\d[\d,\s'’]*\d\b/g, (match) => { - const digits = match.replace(/[^\d]/g, ""); - if (digits.length < 4) return match; - return digits.replace(/\B(?=(\d{3})+(?!\d))/g, " "); - }); + const formatted = protectedText.replace( + /\b(?:\d{4,}|\d{1,3}(?:,\d{3})+|\d{1,3}(?:[ \u00A0\u202F]\d{3})+|\d{1,3}(?:['’]\d{3})+)\b/g, + (match) => { + const digits = match.replace(/[^\d]/g, ""); + return digits.replace(/\B(?=(\d{3})+(?!\d))/g, " "); + } + ); return formatted.replace(/__BG_PROTECTED_(\d+)__/g, (_, i) => protectedParts[Number(i)] ?? ""); } catch {