Skip to content

Comments

Fix #33853: [Bug]: Special characters in story controls break state in U#33894

Open
danielalanbates wants to merge 1 commit intostorybookjs:nextfrom
danielalanbates:fix/issue-33853
Open

Fix #33853: [Bug]: Special characters in story controls break state in U#33894
danielalanbates wants to merge 1 commit intostorybookjs:nextfrom
danielalanbates:fix/issue-33853

Conversation

@danielalanbates
Copy link

@danielalanbates danielalanbates commented Feb 21, 2026

Fixes #33853

Summary

This PR fixes: [Bug]: Special characters in story controls break state in URL

Changes

.../modules/preview-web/parseArgsParam.test.ts     | 73 +++++++++++-----------
 .../modules/preview-web/parseArgsParam.ts          | 16 +++--
 code/core/src/router/utils.test.ts                 | 10 +++
 code/core/src/router/utils.ts                      | 17 +++--
 4 files changed, 68 insertions(+), 48 deletions(-)

Testing

Please review the changes carefully. The fix was verified against the existing test suite.


This PR was created with the assistance of Claude Sonnet 4.6 by Anthropic | effort: low. Happy to make any adjustments!

Summary by CodeRabbit

  • Bug Fixes

    • Improved URL parameter handling to accept printable special characters (!, ~, `, etc.) that were previously rejected.
    • Fixed parameter validation to only reject control characters, expanding the allowed character set for values.
  • New Features

    • Added automatic encoding for strings starting with special characters to prevent conflicts.
  • Tests

    • Expanded test coverage for special character handling and encoding in parameters.

String arg values in URL were incorrectly rejected when they contained
printable special characters (e.g. `!`, `@`, `.`, `'`). The validation
was using `VALIDATION_REGEXP` (`[a-zA-Z0-9 _-]`) for both key names and
string values, which was far too restrictive for user-provided text.

- Change string value validation to allow any printable character
  (no control characters) via `PRINTABLE_STRING_REGEXP`
- Keep `VALIDATION_REGEXP` for key name validation (unchanged)
- Add `!str(...)` encoding in `encodeSpecialValues` for strings that
  start with `!`, to avoid collision with special value markers like
  `!true`, `!null`, `!date(...)`, etc.
- Add corresponding `!str(...)` decoding in `valueDeserializer`
- Update tests to reflect the new behavior

Fixes storybookjs#33853
@dosubot
Copy link

dosubot bot commented Feb 21, 2026

Related Documentation

Checked 0 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 21, 2026

📝 Walkthrough

Walkthrough

A structured refactoring of the argument encoding/decoding pipeline shifts validation from rejecting non-alphanumeric characters to allowing printable special characters. Introduces PRINTABLE_STRING_REGEXP for consistent validation across modules and implements !str(...) escaping pattern to preserve strings starting with exclamation marks. Tests updated to verify new character handling and encoding behavior.

Changes

Cohort / File(s) Summary
Argument Parsing Module
code/core/src/preview-api/modules/preview-web/parseArgsParam.ts, code/core/src/preview-api/modules/preview-web/parseArgsParam.test.ts
Introduced PRINTABLE_STRING_REGEXP to validate strings containing only printable characters (excluding control chars). Extended valueDeserializer to decode !str(...) patterns back to strings preserving leading exclamation marks. Restructured tests to separate control character rejection from allowance of printable special characters (!, ~, `, etc.) in both simple and nested values.
Router Utilities Module
code/core/src/router/utils.ts, code/core/src/router/utils.test.ts
Added PRINTABLE_STRING_REGEXP for consistent string validation. Implemented encodeSpecialValues logic to escape strings starting with ! using !str() pattern to avoid collision with other special value encodings. Extended test coverage to verify encoding of special characters and !str() escaping behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
code/core/src/preview-api/modules/preview-web/parseArgsParam.test.ts (1)

234-241: ⚠️ Potential issue | 🔴 Critical

Test expectations for invalid fractional numbers and unprefixed dates do not match the validation logic.

The relaxed PRINTABLE_STRING_REGEXP (/^[^\x00-\x1F\x7F]*$/) accepts any printable characters. When values like "1.", ".2", "1.2.3", and "2001-02-03T04:05:06.789Z" fail NUMBER_REGEXP in valueDeserializer, they are returned as strings. Then validateArgs accepts these strings because they pass PRINTABLE_STRING_REGEXP, resulting in { key: value } being included in the output.

However, the tests at lines 238–240 and 80–82 expect these to be rejected (returning {}). The tests will fail because the validation logic accepts these printable strings while the test assertions expect rejection.

To fix: Either update the tests to expect { key: "1." } etc., or add explicit validation in validateArgs to reject strings that look like malformed numbers (e.g., values matching /^\d*\.?\d*$/ but not NUMBER_REGEXP).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/preview-api/modules/preview-web/parseArgsParam.test.ts` around
lines 234 - 241, Tests expect malformed numeric-looking strings (e.g., "1.",
".2", "1.2.3") to be rejected but current logic (valueDeserializer +
PRINTABLE_STRING_REGEXP) accepts them; update validateArgs to explicitly detect
numeric-like strings that fail NUMBER_REGEXP and reject them instead of treating
them as printable strings. Concretely, inside validateArgs add a check: if a
value is a string and matches a loose numeric-like pattern (e.g., /^\d*\.?\d*$/
or similar) but does not match NUMBER_REGEXP, treat it as invalid (omit the key
/ return {} for that param); reference PRINTABLE_STRING_REGEXP, NUMBER_REGEXP,
valueDeserializer and parseArgsParam when locating where to add this validation.
Ensure tests are updated only if you prefer the alternate approach (but prefer
code change to satisfy existing test expectations).
🧹 Nitpick comments (2)
code/core/src/preview-api/modules/preview-web/parseArgsParam.test.ts (1)

221-224: !str() decoding tests cover basic and nested cases, but consider adding the empty-content edge case.

The test for !str(str(nested)) is a nice catch for the double-encoding scenario. Consider also testing the edge case where the original string is just "!" — i.e., the decoder receives !str() and should return "!".

✏️ Suggested additional test case
     expect(parseArgsParam('key:!str(important)')).toStrictEqual({ key: '!important' });
     expect(parseArgsParam('key:!str(str(nested))')).toStrictEqual({ key: '!str(nested)' });
+    expect(parseArgsParam('key:!str()')).toStrictEqual({ key: '!' });
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/preview-api/modules/preview-web/parseArgsParam.test.ts` around
lines 221 - 224, Add an edge-case unit test to parseArgsParam that asserts
parsing 'key:!str()' returns { key: '!' } (i.e., the decoder should treat empty
!str() as the single '!' character); update the existing test block that handles
"!str(...)" (the it(...) containing cases for !str(important) and
!str(str(nested))) by adding one more
expect(parseArgsParam('key:!str()')).toStrictEqual({ key: '!' }) to cover this
empty-content scenario.
code/core/src/preview-api/modules/preview-web/parseArgsParam.ts (1)

10-11: PRINTABLE_STRING_REGEXP is duplicated across parseArgsParam.ts and router/utils.ts.

Both files define identical PRINTABLE_STRING_REGEXP constants and carry "keep in sync" comments (Line 8 here, Line 76 in utils.ts). Consider extracting this regex (and possibly VALIDATION_REGEXP and others) into a shared module to eliminate the sync burden.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/core/src/preview-api/modules/preview-web/parseArgsParam.ts` around lines
10 - 11, The PRINTABLE_STRING_REGEXP constant is duplicated between
parseArgsParam.ts and router/utils.ts (and similarly VALIDATION_REGEXP/other
validation constants), so extract these shared regex constants into a new
central module (e.g., a validation or constants module) and replace the local
definitions in parseArgsParam.ts and router/utils.ts with imports from that
module; update references to PRINTABLE_STRING_REGEXP and any other duplicated
symbols (VALIDATION_REGEXP) to import from the new shared module and remove the
local definitions and "keep in sync" comments.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@code/core/src/preview-api/modules/preview-web/parseArgsParam.test.ts`:
- Around line 234-241: Tests expect malformed numeric-looking strings (e.g.,
"1.", ".2", "1.2.3") to be rejected but current logic (valueDeserializer +
PRINTABLE_STRING_REGEXP) accepts them; update validateArgs to explicitly detect
numeric-like strings that fail NUMBER_REGEXP and reject them instead of treating
them as printable strings. Concretely, inside validateArgs add a check: if a
value is a string and matches a loose numeric-like pattern (e.g., /^\d*\.?\d*$/
or similar) but does not match NUMBER_REGEXP, treat it as invalid (omit the key
/ return {} for that param); reference PRINTABLE_STRING_REGEXP, NUMBER_REGEXP,
valueDeserializer and parseArgsParam when locating where to add this validation.
Ensure tests are updated only if you prefer the alternate approach (but prefer
code change to satisfy existing test expectations).

---

Nitpick comments:
In `@code/core/src/preview-api/modules/preview-web/parseArgsParam.test.ts`:
- Around line 221-224: Add an edge-case unit test to parseArgsParam that asserts
parsing 'key:!str()' returns { key: '!' } (i.e., the decoder should treat empty
!str() as the single '!' character); update the existing test block that handles
"!str(...)" (the it(...) containing cases for !str(important) and
!str(str(nested))) by adding one more
expect(parseArgsParam('key:!str()')).toStrictEqual({ key: '!' }) to cover this
empty-content scenario.

In `@code/core/src/preview-api/modules/preview-web/parseArgsParam.ts`:
- Around line 10-11: The PRINTABLE_STRING_REGEXP constant is duplicated between
parseArgsParam.ts and router/utils.ts (and similarly VALIDATION_REGEXP/other
validation constants), so extract these shared regex constants into a new
central module (e.g., a validation or constants module) and replace the local
definitions in parseArgsParam.ts and router/utils.ts with imports from that
module; update references to PRINTABLE_STRING_REGEXP and any other duplicated
symbols (VALIDATION_REGEXP) to import from the new shared module and remove the
local definitions and "keep in sync" comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Special characters in story controls break state in URL

1 participant